This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
dynamically disable leb128 for relaxation
- From: Christian BRUEL <christian dot bruel at st dot com>
- To: binutils at sourceware dot org, GCC Patches <gcc-patches at gcc dot gnu dot org>
- Cc: Kaz Kojima <kkojima at rr dot iij4u dot or dot jp>, Yvan ROUX <yvan dot roux at st dot com>
- Date: Mon, 17 Aug 2009 14:12:21 +0200
- Subject: dynamically disable leb128 for relaxation
The exceptions regions range's size in the FDEs are compressed by the
assembler into ULEB128 when available. However the linker can post
modify those size when relaxing code. Since the label relocations are
not available anymore, no reparation can be done, and the exceptions
handler are not associated with the correct range labels which leads to
runtime failures.
The "correct" answer would be to delay the LEB128 compression from the
assembler to the linker, after the labels are resolved and the
difference computed, however this is a non trivial work, and the C++
relaxed code is today broken for targets supporting relaxation.
(see http://sourceware.org/ml/binutils/2009-08/msg00124.html and
(http://sourceware.org/ml/binutils/2009-08/msg00192.html. threads)
This patch is a conservative approach before the LEB128 support is added
into the linker to dynamically test the LEB128 support instead of having
it a compile time parameter. Ideally, only ULEB128 differences between
labels should be discarted, but since the FDE call site format doesn't
distinguish it, all constants must be impacted. Consequently, with this
scheme relaxation, exceptions and optimizing for size do not go well
together :-( ) but this is better than false code gen.
We have used this workaround for SH4 during our current relaxation
developments, but if it can help also the other targets that are facing
the same issue, I'd like to receive comments or OK to ci.
tested for regression on i686-pc-linux-gnu and sh-superh-elf.
Best Regards
-c
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi (revision 150822)
+++ gcc/doc/tm.texi (working copy)
@@ -3488,6 +3488,13 @@
linkage is necessary. The default is @code{0}.
@end defmac
+@defmac TARGET_USES_LEB128
+A C expression that evaluates to true if the target requires leb128
+to be used for dwarf compression. Define it to be @code{1} if leb128
+linkage is necessary. The default is @code{1} if @code{HAVE_AS_LEB128}
+is defined.
+@end defmac
+
@node Stack Checking
@subsection Specifying How Stack Checking is Done
Index: gcc/dwarf2asm.c
===================================================================
--- gcc/dwarf2asm.c (revision 150822)
+++ gcc/dwarf2asm.c (working copy)
@@ -564,52 +564,54 @@
va_start (ap, comment);
-#ifdef HAVE_AS_LEB128
- fprintf (asm_out_file, "\t.uleb128 " HOST_WIDE_INT_PRINT_HEX , value);
+ if (TARGET_USES_LEB128)
+ {
+ fprintf (asm_out_file, "\t.uleb128 " HOST_WIDE_INT_PRINT_HEX , value);
- if (flag_debug_asm && comment)
+ if (flag_debug_asm && comment)
+ {
+ fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
+ vfprintf (asm_out_file, comment, ap);
+ }
+ }
+ else
{
- fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
- vfprintf (asm_out_file, comment, ap);
- }
-#else
- {
- unsigned HOST_WIDE_INT work = value;
- const char *byte_op = targetm.asm_out.byte_op;
+ unsigned HOST_WIDE_INT work = value;
+ const char *byte_op = targetm.asm_out.byte_op;
- if (byte_op)
- fputs (byte_op, asm_out_file);
- do
- {
- int byte = (work & 0x7f);
- work >>= 7;
- if (work != 0)
- /* More bytes to follow. */
- byte |= 0x80;
+ if (byte_op)
+ fputs (byte_op, asm_out_file);
+ do
+ {
+ int byte = (work & 0x7f);
+ work >>= 7;
+ if (work != 0)
+ /* More bytes to follow. */
+ byte |= 0x80;
- if (byte_op)
- {
- fprintf (asm_out_file, "0x%x", byte);
- if (work != 0)
- fputc (',', asm_out_file);
- }
- else
- assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
- }
- while (work != 0);
-
- if (flag_debug_asm)
- {
- fprintf (asm_out_file, "\t%s uleb128 " HOST_WIDE_INT_PRINT_HEX,
- ASM_COMMENT_START, value);
- if (comment)
+ if (byte_op)
+ {
+ fprintf (asm_out_file, "0x%x", byte);
+ if (work != 0)
+ fputc (',', asm_out_file);
+ }
+ else
+ assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
+ }
+ while (work != 0);
+
+ if (flag_debug_asm)
{
- fputs ("; ", asm_out_file);
- vfprintf (asm_out_file, comment, ap);
+ fprintf (asm_out_file, "\t%s uleb128 " HOST_WIDE_INT_PRINT_HEX,
+ ASM_COMMENT_START, value);
+ if (comment)
+ {
+ fputs ("; ", asm_out_file);
+ vfprintf (asm_out_file, comment, ap);
+ }
}
}
- }
-#endif
+
fputc ('\n', asm_out_file);
va_end (ap);
@@ -648,55 +650,57 @@
va_start (ap, comment);
-#ifdef HAVE_AS_LEB128
- fprintf (asm_out_file, "\t.sleb128 " HOST_WIDE_INT_PRINT_DEC, value);
+ if (TARGET_USES_LEB128)
+ {
+ fprintf (asm_out_file, "\t.sleb128 " HOST_WIDE_INT_PRINT_DEC, value);
- if (flag_debug_asm && comment)
+ if (flag_debug_asm && comment)
+ {
+ fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
+ vfprintf (asm_out_file, comment, ap);
+ }
+ }
+ else
{
- fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
- vfprintf (asm_out_file, comment, ap);
- }
-#else
- {
- HOST_WIDE_INT work = value;
- int more, byte;
- const char *byte_op = targetm.asm_out.byte_op;
+ HOST_WIDE_INT work = value;
+ int more, byte;
+ const char *byte_op = targetm.asm_out.byte_op;
- if (byte_op)
- fputs (byte_op, asm_out_file);
- do
- {
- byte = (work & 0x7f);
- /* arithmetic shift */
- work >>= 7;
- more = !((work == 0 && (byte & 0x40) == 0)
- || (work == -1 && (byte & 0x40) != 0));
- if (more)
- byte |= 0x80;
+ if (byte_op)
+ fputs (byte_op, asm_out_file);
+ do
+ {
+ byte = (work & 0x7f);
+ /* arithmetic shift */
+ work >>= 7;
+ more = !((work == 0 && (byte & 0x40) == 0)
+ || (work == -1 && (byte & 0x40) != 0));
+ if (more)
+ byte |= 0x80;
- if (byte_op)
- {
- fprintf (asm_out_file, "0x%x", byte);
- if (more)
- fputc (',', asm_out_file);
- }
- else
- assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
- }
- while (more);
+ if (byte_op)
+ {
+ fprintf (asm_out_file, "0x%x", byte);
+ if (more)
+ fputc (',', asm_out_file);
+ }
+ else
+ assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
+ }
+ while (more);
- if (flag_debug_asm)
- {
- fprintf (asm_out_file, "\t%s sleb128 " HOST_WIDE_INT_PRINT_DEC,
- ASM_COMMENT_START, value);
- if (comment)
+ if (flag_debug_asm)
{
- fputs ("; ", asm_out_file);
- vfprintf (asm_out_file, comment, ap);
+ fprintf (asm_out_file, "\t%s sleb128 " HOST_WIDE_INT_PRINT_DEC,
+ ASM_COMMENT_START, value);
+ if (comment)
+ {
+ fputs ("; ", asm_out_file);
+ vfprintf (asm_out_file, comment, ap);
+ }
}
}
- }
-#endif
+
fputc ('\n', asm_out_file);
va_end (ap);
@@ -711,14 +715,15 @@
va_start (ap, comment);
-#ifdef HAVE_AS_LEB128
- fputs ("\t.uleb128 ", asm_out_file);
- assemble_name (asm_out_file, lab1);
- fputc ('-', asm_out_file);
- assemble_name (asm_out_file, lab2);
-#else
- gcc_unreachable ();
-#endif
+ if (TARGET_USES_LEB128)
+ {
+ fputs ("\t.uleb128 ", asm_out_file);
+ assemble_name (asm_out_file, lab1);
+ fputc ('-', asm_out_file);
+ assemble_name (asm_out_file, lab2);
+ }
+ else
+ gcc_unreachable ();
if (flag_debug_asm && comment)
{
@@ -741,14 +746,15 @@
va_start (ap, comment);
-#ifdef HAVE_AS_LEB128
- fputs ("\t.sleb128 ", asm_out_file);
- assemble_name (asm_out_file, lab1);
- fputc ('-', asm_out_file);
- assemble_name (asm_out_file, lab2);
-#else
- gcc_unreachable ();
-#endif
+ if (TARGET_USES_LEB128)
+ {
+ fputs ("\t.sleb128 ", asm_out_file);
+ assemble_name (asm_out_file, lab1);
+ fputc ('-', asm_out_file);
+ assemble_name (asm_out_file, lab2);
+ }
+ else
+ gcc_unreachable ();
if (flag_debug_asm && comment)
{
Index: gcc/defaults.h
===================================================================
--- gcc/defaults.h (revision 150822)
+++ gcc/defaults.h (working copy)
@@ -288,6 +288,15 @@
#define TARGET_USES_WEAK_UNWIND_INFO 0
#endif
+/* Use leb128 encoding based on dynamic parameters. */
+#ifndef TARGET_USES_LEB128
+#ifdef HAVE_AS_LEB128
+#define TARGET_USES_LEB128 1
+#else
+#define TARGET_USES_LEB128 0
+#endif
+#endif
+
/* By default, there is no prefix on user-defined symbols. */
#ifndef USER_LABEL_PREFIX
#define USER_LABEL_PREFIX ""
Index: gcc/except.c
===================================================================
--- gcc/except.c (revision 150822)
+++ gcc/except.c (working copy)
@@ -173,10 +173,10 @@
static void push_uleb128 (varray_type *, unsigned int);
static void push_sleb128 (varray_type *, int);
-#ifndef HAVE_AS_LEB128
+
static int dw2_size_of_call_site_table (int);
static int sjlj_size_of_call_site_table (void);
-#endif
+
static void dw2_output_call_site_table (int, int);
static void sjlj_output_call_site_table (void);
@@ -4139,7 +4139,6 @@
}
-#ifndef HAVE_AS_LEB128
static int
dw2_size_of_call_site_table (int section)
{
@@ -4174,7 +4173,6 @@
return size;
}
-#endif
static void
dw2_output_call_site_table (int cs_format, int section)
@@ -4364,13 +4362,10 @@
int section)
{
int tt_format, cs_format, lp_format, i, n;
-#ifdef HAVE_AS_LEB128
char ttype_label[32];
char cs_after_size_label[32];
char cs_end_label[32];
-#else
int call_site_len;
-#endif
int have_tt_data;
int tt_format_size = 0;
@@ -4397,11 +4392,11 @@
else
{
tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
-#ifdef HAVE_AS_LEB128
- ASM_GENERATE_INTERNAL_LABEL (ttype_label,
- section ? "LLSDATTC" : "LLSDATT",
- current_function_funcdef_no);
-#endif
+ if (TARGET_USES_LEB128)
+ ASM_GENERATE_INTERNAL_LABEL (ttype_label,
+ section ? "LLSDATTC" : "LLSDATT",
+ current_function_funcdef_no);
+
tt_format_size = size_of_encoded_value (tt_format);
assemble_align (tt_format_size * BITS_PER_UNIT);
@@ -4427,86 +4422,93 @@
dw2_asm_output_data (1, tt_format, "@TType format (%s)",
eh_data_format_name (tt_format));
-#ifndef HAVE_AS_LEB128
- if (USING_SJLJ_EXCEPTIONS)
- call_site_len = sjlj_size_of_call_site_table ();
- else
- call_site_len = dw2_size_of_call_site_table (section);
-#endif
+ if (! TARGET_USES_LEB128)
+ {
+ if (USING_SJLJ_EXCEPTIONS)
+ call_site_len = sjlj_size_of_call_site_table ();
+ else
+ call_site_len = dw2_size_of_call_site_table (section);
+ }
/* A pc-relative 4-byte displacement to the @TType data. */
if (have_tt_data)
{
-#ifdef HAVE_AS_LEB128
- char ttype_after_disp_label[32];
- ASM_GENERATE_INTERNAL_LABEL (ttype_after_disp_label,
- section ? "LLSDATTDC" : "LLSDATTD",
- current_function_funcdef_no);
- dw2_asm_output_delta_uleb128 (ttype_label, ttype_after_disp_label,
- "@TType base offset");
- ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label);
-#else
- /* Ug. Alignment queers things. */
- unsigned int before_disp, after_disp, last_disp, disp;
+ if (TARGET_USES_LEB128)
+ {
+ char ttype_after_disp_label[32];
+ ASM_GENERATE_INTERNAL_LABEL (ttype_after_disp_label,
+ section ? "LLSDATTDC" : "LLSDATTD",
+ current_function_funcdef_no);
+ dw2_asm_output_delta_uleb128 (ttype_label, ttype_after_disp_label,
+ "@TType base offset");
+ ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label);
+ }
+ else
+ {
+ /* Ug. Alignment queers things. */
+ unsigned int before_disp, after_disp, last_disp, disp;
- before_disp = 1 + 1;
- after_disp = (1 + size_of_uleb128 (call_site_len)
- + call_site_len
- + VARRAY_ACTIVE_SIZE (crtl->eh.action_record_data)
- + (VEC_length (tree, crtl->eh.ttype_data)
- * tt_format_size));
+ before_disp = 1 + 1;
+ after_disp = (1 + size_of_uleb128 (call_site_len)
+ + call_site_len
+ + VARRAY_ACTIVE_SIZE (crtl->eh.action_record_data)
+ + (VEC_length (tree, crtl->eh.ttype_data)
+ * tt_format_size));
- disp = after_disp;
- do
- {
- unsigned int disp_size, pad;
+ disp = after_disp;
+ do
+ {
+ unsigned int disp_size, pad;
- last_disp = disp;
- disp_size = size_of_uleb128 (disp);
- pad = before_disp + disp_size + after_disp;
- if (pad % tt_format_size)
- pad = tt_format_size - (pad % tt_format_size);
- else
- pad = 0;
- disp = after_disp + pad;
+ last_disp = disp;
+ disp_size = size_of_uleb128 (disp);
+ pad = before_disp + disp_size + after_disp;
+ if (pad % tt_format_size)
+ pad = tt_format_size - (pad % tt_format_size);
+ else
+ pad = 0;
+ disp = after_disp + pad;
+ }
+ while (disp != last_disp);
+
+ dw2_asm_output_data_uleb128 (disp, "@TType base offset");
}
- while (disp != last_disp);
-
- dw2_asm_output_data_uleb128 (disp, "@TType base offset");
-#endif
}
/* Indicate the format of the call-site offsets. */
-#ifdef HAVE_AS_LEB128
- cs_format = DW_EH_PE_uleb128;
-#else
- cs_format = DW_EH_PE_udata4;
-#endif
+ if (TARGET_USES_LEB128)
+ cs_format = DW_EH_PE_uleb128;
+ else
+ cs_format = DW_EH_PE_udata4;
+
dw2_asm_output_data (1, cs_format, "call-site format (%s)",
eh_data_format_name (cs_format));
-#ifdef HAVE_AS_LEB128
- ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label,
- section ? "LLSDACSBC" : "LLSDACSB",
- current_function_funcdef_no);
- ASM_GENERATE_INTERNAL_LABEL (cs_end_label,
- section ? "LLSDACSEC" : "LLSDACSE",
- current_function_funcdef_no);
- dw2_asm_output_delta_uleb128 (cs_end_label, cs_after_size_label,
- "Call-site table length");
- ASM_OUTPUT_LABEL (asm_out_file, cs_after_size_label);
- if (USING_SJLJ_EXCEPTIONS)
- sjlj_output_call_site_table ();
+ if (TARGET_USES_LEB128)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label,
+ section ? "LLSDACSBC" : "LLSDACSB",
+ current_function_funcdef_no);
+ ASM_GENERATE_INTERNAL_LABEL (cs_end_label,
+ section ? "LLSDACSEC" : "LLSDACSE",
+ current_function_funcdef_no);
+ dw2_asm_output_delta_uleb128 (cs_end_label, cs_after_size_label,
+ "Call-site table length");
+ ASM_OUTPUT_LABEL (asm_out_file, cs_after_size_label);
+ if (USING_SJLJ_EXCEPTIONS)
+ sjlj_output_call_site_table ();
+ else
+ dw2_output_call_site_table (cs_format, section);
+ ASM_OUTPUT_LABEL (asm_out_file, cs_end_label);
+ }
else
- dw2_output_call_site_table (cs_format, section);
- ASM_OUTPUT_LABEL (asm_out_file, cs_end_label);
-#else
- dw2_asm_output_data_uleb128 (call_site_len, "Call-site table length");
- if (USING_SJLJ_EXCEPTIONS)
- sjlj_output_call_site_table ();
- else
- dw2_output_call_site_table (cs_format, section);
-#endif
+ {
+ dw2_asm_output_data_uleb128 (call_site_len, "Call-site table length");
+ if (USING_SJLJ_EXCEPTIONS)
+ sjlj_output_call_site_table ();
+ else
+ dw2_output_call_site_table (cs_format, section);
+ }
/* ??? Decode and interpret the data for flag_debug_asm. */
n = VARRAY_ACTIVE_SIZE (crtl->eh.action_record_data);
@@ -4524,10 +4526,8 @@
output_ttype (type, tt_format, tt_format_size);
}
-#ifdef HAVE_AS_LEB128
- if (have_tt_data)
- ASM_OUTPUT_LABEL (asm_out_file, ttype_label);
-#endif
+ if (TARGET_USES_LEB128 && have_tt_data)
+ ASM_OUTPUT_LABEL (asm_out_file, ttype_label);
/* ??? Decode and interpret the data for flag_debug_asm. */
n = VARRAY_ACTIVE_SIZE (crtl->eh.ehspec_data);
Index: gcc/config/sh/sh.h
===================================================================
--- gcc/config/sh/sh.h (revision 150822)
+++ gcc/config/sh/sh.h (working copy)
@@ -2847,4 +2847,7 @@
/* FIXME: middle-end support for highpart optimizations is missing. */
#define high_life_started reload_in_progress
+#define TARGET_USES_LEB128 \
+ (! TARGET_RELAX || (!flag_unwind_tables && !flag_exceptions))
+
#endif /* ! GCC_SH_H */
2009-04-12 Christian Bruel <christian.bruel@st.com>
* default.h (TARGET_USES_LEB128): New macro.
* doc/tm.texi (TARGET_USES_LEB128): Likewise.
* config/sh/sh.h (TARGET_USES_LEB128): Redefine.
* dwarf2asm.c (TARGET_USES_LEB128): Use instead of HAVE_AS_LEB128.
* except.c: Likewise.