diff --git a/gcc/config.in b/gcc/config.in index ae41596596fab82dd512a53ae5c73c7a523b01b4..bc819005bd62454d0b09cc42bbb7123d31ea8905 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -1437,6 +1437,12 @@ #endif +/* Define if your assembler supports .base64. */ +#ifndef USED_FOR_TARGET +#undef HAVE_GAS_BASE64 +#endif + + /* Define 0/1 if your assembler supports CFI directives. */ #undef HAVE_GAS_CFI_DIRECTIVE diff --git a/gcc/config/elfos.h b/gcc/config/elfos.h index da45593fb3055cc1543d9f1463ba5f50456888fd..133881509df2730ec700d9e68b2d3e57d439023b 100644 --- a/gcc/config/elfos.h +++ b/gcc/config/elfos.h @@ -444,6 +444,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define STRING_ASM_OP "\t.string\t" +#ifdef HAVE_GAS_BASE64 +#define BASE64_ASM_OP "\t.base64\t" +#endif + /* The routine used to output NUL terminated strings. We use a special version of this for most svr4 targets because doing so makes the generated assembly code more compact (and thus faster to assemble) diff --git a/gcc/configure b/gcc/configure index 1335db2d4d2e5a70012006457a467ce67fe6bf69..4faae0fa5fb877539722c5ca32e0377f5e86a158 100755 --- a/gcc/configure +++ b/gcc/configure @@ -25859,6 +25859,39 @@ case "${target}" in ;; esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .base64" >&5 +$as_echo_n "checking assembler for .base64... " >&6; } +if ${gcc_cv_as_base64+:} false; then : + $as_echo_n "(cached) " >&6 +else + gcc_cv_as_base64=no + if test x$gcc_cv_as != x; then + $as_echo ' .section .rodata + .base64 "Tm9uIHB1ZG9yIGVzdCBuaWwgc2NpcmUsIHB1ZG9yIG5pbCBkaXNjZXJlIHZlbGxlLgo="' > conftest.s + if { ac_try='$gcc_cv_as $gcc_cv_as_flags -o conftest.o conftest.s >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } + then + gcc_cv_as_base64=yes + else + echo "configure: failed program was" >&5 + cat conftest.s >&5 + fi + rm -f conftest.o conftest.s + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_base64" >&5 +$as_echo "$gcc_cv_as_base64" >&6; } +if test $gcc_cv_as_base64 = yes; then + +$as_echo "#define HAVE_GAS_BASE64 1" >>confdefs.h + +fi + + # gnu_indirect_function type is an extension proposed at # http://groups.google/com/group/generic-abi/files. It allows dynamic runtime # selection of function implementation diff --git a/gcc/configure.ac b/gcc/configure.ac index eb72f65865ab7167894be827b7c303caaf56636e..3da1eaa706461e1e4a5284e59743377ddbc16c87 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -3054,6 +3054,11 @@ case "${target}" in ;; esac +gcc_GAS_CHECK_FEATURE([.base64], gcc_cv_as_base64,, + [ .section .rodata + .base64 "Tm9uIHB1ZG9yIGVzdCBuaWwgc2NpcmUsIHB1ZG9yIG5pbCBkaXNjZXJlIHZlbGxlLgo="],, +[AC_DEFINE(HAVE_GAS_BASE64, 1, [Define if your assembler supports .base64.])]) + # gnu_indirect_function type is an extension proposed at # http://groups.google/com/group/generic-abi/files. It allows dynamic runtime # selection of function implementation diff --git a/gcc/varasm.cc b/gcc/varasm.cc index a6ef099c3641f694f92de39785a0dc00cd278067..fe0a6b873ef4da833952cfdf1e16bdc79756f79c 100644 --- a/gcc/varasm.cc +++ b/gcc/varasm.cc @@ -2101,7 +2101,19 @@ void assemble_string (const char *p, int size) { int pos = 0; +#if defined(BASE64_ASM_OP) \ + && BITS_PER_UNIT == 8 \ + && CHAR_BIT == 8 \ + && 'A' == 65 \ + && 'a' == 97 \ + && '0' == 48 \ + && '+' == 43 \ + && '/' == 47 \ + && '=' == 61 + int maximum = 16384; +#else int maximum = 2000; +#endif /* If the string is very long, split it up. */ @@ -8454,8 +8466,7 @@ default_elf_asm_output_limited_string (FILE *f, const char *s) int escape; unsigned char c; - fputs (STRING_ASM_OP, f); - putc ('"', f); + fputs (STRING_ASM_OP "\"", f); while (*s != '\0') { c = *s; @@ -8489,9 +8500,11 @@ default_elf_asm_output_ascii (FILE *f, const char *s, unsigned int len) { const char *limit = s + len; const char *last_null = NULL; + const char *last_base64 = s; unsigned bytes_in_chunk = 0; unsigned char c; int escape; + bool prev_base64 = false; for (; s < limit; s++) { @@ -8504,7 +8517,7 @@ default_elf_asm_output_ascii (FILE *f, const char *s, unsigned int len) bytes_in_chunk = 0; } - if (s > last_null) + if ((uintptr_t) s > (uintptr_t) last_null) { for (p = s; p < limit && *p != '\0'; p++) continue; @@ -8513,6 +8526,104 @@ default_elf_asm_output_ascii (FILE *f, const char *s, unsigned int len) else p = last_null; +#if defined(BASE64_ASM_OP) \ + && BITS_PER_UNIT == 8 \ + && CHAR_BIT == 8 \ + && 'A' == 65 \ + && 'a' == 97 \ + && '0' == 48 \ + && '+' == 43 \ + && '/' == 47 \ + && '=' == 61 + if (s >= last_base64) + { + unsigned cnt = 0; + const char *t; + for (t = s; t < limit && (t - s) < (long) ELF_STRING_LIMIT - 1; t++) + { + if (t == p && t != s) + { + if (cnt <= (t - s + 1 + 2) / 3 * 4 + && (!prev_base64 || (t - s) >= 16) + && ((t - s) > 1 || cnt <= 2)) + { + last_base64 = p; + goto no_base64; + } + } + c = *t; + escape = ELF_ASCII_ESCAPES[c]; + switch (escape) + { + case 0: + ++cnt; + break; + case 1: + if (c == 0) + cnt += 2 + strlen (STRING_ASM_OP) + 1; + else + cnt += 4; + break; + default: + cnt += 2; + break; + } + } + if (cnt > (t - s + 2) / 3 * 4 && (t - s) >= 3) + { + if (bytes_in_chunk > 0) + { + putc ('\"', f); + putc ('\n', f); + bytes_in_chunk = 0; + } + + unsigned char buf[(ELF_STRING_LIMIT + 2) / 3 * 4 + 3]; + unsigned j = 0; + static const char base64_enc[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + fputs (BASE64_ASM_OP "\"", f); + while (s < t) + { + unsigned char a = *s; + unsigned char b = 0, c = 0; + if (s < t - 1) + b = s[1]; + if (s < t - 2) + c = s[2]; + unsigned long v = ((((unsigned long) a) << 16) + | (((unsigned long) b) << 8) + | c); + buf[j++] = base64_enc[(v >> 18) & 63]; + buf[j++] = base64_enc[(v >> 12) & 63]; + buf[j++] = base64_enc[(v >> 6) & 63]; + buf[j++] = base64_enc[v & 63]; + if (s >= t - 2) + { + buf[j - 1] = '='; + if (s >= t - 1) + buf[j - 2] = '='; + break; + } + s += 3; + } + memcpy (buf + j, "\"\n", 3); + fputs ((const char *) buf, f); + s = t - 1; + prev_base64 = true; + continue; + } + last_base64 = t; + no_base64: + prev_base64 = false; + } +#else + (void) last_base64; + (void) prev_base64; +#endif + if (p < limit && (p - s) <= (long) ELF_STRING_LIMIT) { if (bytes_in_chunk > 0)