From 8529ddd3cf8b8ffce3ab6c5b64acddb7831726a7 Mon Sep 17 00:00:00 2001 From: kettenis Date: Mon, 18 May 2015 18:38:49 +0000 Subject: [PATCH] Make the compiler emit visibility information for (undefined) references with non-default visibility. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=20218 for details. This version comes from FreeBSD and has been made available under the GPLv2 license. It has some additional bits thrown in from me to make it work in mips64 too, and another bit to stop the C++ compiler to randomly emit visibility information for C++ symbols that in the end aren't referenced. ok guenther@ --- gnu/gcc/gcc/cgraphunit.c | 2 - gnu/gcc/gcc/config/elfos.h | 10 +++ gnu/gcc/gcc/config/ia64/hpux.h | 4 -- gnu/gcc/gcc/config/ia64/ia64.c | 113 +++++++-------------------------- gnu/gcc/gcc/cp/decl2.c | 2 - gnu/gcc/gcc/output.h | 10 ++- gnu/gcc/gcc/toplev.c | 4 +- gnu/gcc/gcc/varasm.c | 34 +++++++--- 8 files changed, 66 insertions(+), 113 deletions(-) diff --git a/gnu/gcc/gcc/cgraphunit.c b/gnu/gcc/gcc/cgraphunit.c index 0d3ed477f9d..6d6ce2f1b42 100644 --- a/gnu/gcc/gcc/cgraphunit.c +++ b/gnu/gcc/gcc/cgraphunit.c @@ -1536,8 +1536,6 @@ cgraph_optimize (void) return; } - process_pending_assemble_externals (); - /* Frontend may output common variables after the unit has been finalized. It is safe to deal with them here as they are always zero initialized. */ cgraph_varpool_analyze_pending_decls (); diff --git a/gnu/gcc/gcc/config/elfos.h b/gnu/gcc/gcc/config/elfos.h index a2bd49f909a..96a8e850b00 100644 --- a/gnu/gcc/gcc/config/elfos.h +++ b/gnu/gcc/gcc/config/elfos.h @@ -496,3 +496,13 @@ Boston, MA 02110-1301, USA. */ fprintf ((FILE), "\"\n"); \ } \ while (0) + +/* A C statement (sans semicolon) to output to the stdio stream STREAM + any text necessary for declaring the name of an external symbol + named NAME whch is referenced in this compilation but not defined. + It is needed to properly support non-default visibility. */ + +#ifndef ASM_OUTPUT_EXTERNAL +#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \ + default_elf_asm_output_external (FILE, DECL, NAME) +#endif diff --git a/gnu/gcc/gcc/config/ia64/hpux.h b/gnu/gcc/gcc/config/ia64/hpux.h index 996b7d21aa0..bdf3968e95c 100644 --- a/gnu/gcc/gcc/config/ia64/hpux.h +++ b/gnu/gcc/gcc/config/ia64/hpux.h @@ -144,10 +144,6 @@ do { \ definitions, so do not use them in gthr-posix.h. */ #define GTHREAD_USE_WEAK 0 -/* Put out the needed function declarations at the end. */ - -#define TARGET_ASM_FILE_END ia64_hpux_file_end - #undef CTORS_SECTION_ASM_OP #define CTORS_SECTION_ASM_OP "\t.section\t.init_array,\t\"aw\",\"init_array\"" diff --git a/gnu/gcc/gcc/config/ia64/ia64.c b/gnu/gcc/gcc/config/ia64/ia64.c index 6ddff326a5c..2bbc9a707c1 100644 --- a/gnu/gcc/gcc/config/ia64/ia64.c +++ b/gnu/gcc/gcc/config/ia64/ia64.c @@ -250,10 +250,6 @@ static section *ia64_select_rtx_section (enum machine_mode, rtx, static void ia64_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED; static unsigned int ia64_section_type_flags (tree, const char *, int); -static void ia64_hpux_add_extern_decl (tree decl) - ATTRIBUTE_UNUSED; -static void ia64_hpux_file_end (void) - ATTRIBUTE_UNUSED; static void ia64_init_libfuncs (void) ATTRIBUTE_UNUSED; static void ia64_hpux_init_libfuncs (void) @@ -5015,49 +5011,6 @@ ia64_secondary_reload_class (enum reg_class class, } -/* Emit text to declare externally defined variables and functions, because - the Intel assembler does not support undefined externals. */ - -void -ia64_asm_output_external (FILE *file, tree decl, const char *name) -{ - int save_referenced; - - /* GNU as does not need anything here, but the HP linker does need - something for external functions. */ - - if (TARGET_GNU_AS - && (!TARGET_HPUX_LD - || TREE_CODE (decl) != FUNCTION_DECL - || strstr (name, "__builtin_") == name)) - return; - - /* ??? The Intel assembler creates a reference that needs to be satisfied by - the linker when we do this, so we need to be careful not to do this for - builtin functions which have no library equivalent. Unfortunately, we - can't tell here whether or not a function will actually be called by - expand_expr, so we pull in library functions even if we may not need - them later. */ - if (! strcmp (name, "__builtin_next_arg") - || ! strcmp (name, "alloca") - || ! strcmp (name, "__builtin_constant_p") - || ! strcmp (name, "__builtin_args_info")) - return; - - if (TARGET_HPUX_LD) - ia64_hpux_add_extern_decl (decl); - else - { - /* assemble_name will set TREE_SYMBOL_REFERENCED, so we must save and - restore it. */ - save_referenced = TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)); - if (TREE_CODE (decl) == FUNCTION_DECL) - ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function"); - (*targetm.asm_out.globalize_label) (file, name); - TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) = save_referenced; - } -} - /* Parse the -mfixed-range= option string. */ static void @@ -9223,55 +9176,33 @@ ia64_hpux_function_arg_padding (enum machine_mode mode, tree type) return DEFAULT_FUNCTION_ARG_PADDING (mode, type); } -/* Linked list of all external functions that are to be emitted by GCC. - We output the name if and only if TREE_SYMBOL_REFERENCED is set in - order to avoid putting out names that are never really used. */ - -struct extern_func_list GTY(()) -{ - struct extern_func_list *next; - tree decl; -}; - -static GTY(()) struct extern_func_list *extern_func_head; - -static void -ia64_hpux_add_extern_decl (tree decl) -{ - struct extern_func_list *p = ggc_alloc (sizeof (struct extern_func_list)); - - p->decl = decl; - p->next = extern_func_head; - extern_func_head = p; -} - -/* Print out the list of used global functions. */ +/* Emit text to declare externally defined variables and functions, because + the Intel assembler does not support undefined externals. */ -static void -ia64_hpux_file_end (void) +void +ia64_asm_output_external (FILE *file, tree decl, const char *name) { - struct extern_func_list *p; - - for (p = extern_func_head; p; p = p->next) + /* We output the name if and only if TREE_SYMBOL_REFERENCED is + set in order to avoid putting out names that are never really + used. */ + if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) { - tree decl = p->decl; - tree id = DECL_ASSEMBLER_NAME (decl); - - gcc_assert (id); - - if (!TREE_ASM_WRITTEN (decl) && TREE_SYMBOL_REFERENCED (id)) - { - const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0); + /* maybe_assemble_visibility will return 1 if the assembler + visibility directive is outputed. */ + int need_visibility = ((*targetm.binds_local_p) (decl) + && maybe_assemble_visibility (decl)); - TREE_ASM_WRITTEN (decl) = 1; - (*targetm.asm_out.globalize_label) (asm_out_file, name); - fputs (TYPE_ASM_OP, asm_out_file); - assemble_name (asm_out_file, name); - fprintf (asm_out_file, "," TYPE_OPERAND_FMT "\n", "function"); - } + /* GNU as does not need anything here, but the HP linker does + need something for external functions. */ + if ((TARGET_HPUX_LD || !TARGET_GNU_AS) + && TREE_CODE (decl) == FUNCTION_DECL) + { + ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function"); + (*targetm.asm_out.globalize_label) (file, name); + } + else if (need_visibility && !TARGET_GNU_AS) + (*targetm.asm_out.globalize_label) (file, name); } - - extern_func_head = 0; } /* Set SImode div/mod functions, init_integral_libfuncs only initializes diff --git a/gnu/gcc/gcc/cp/decl2.c b/gnu/gcc/gcc/cp/decl2.c index 00bcc16b7a5..2dbbc02eae9 100644 --- a/gnu/gcc/gcc/cp/decl2.c +++ b/gnu/gcc/gcc/cp/decl2.c @@ -3535,8 +3535,6 @@ mark_used (tree decl) note_vague_linkage_fn (decl); } - assemble_external (decl); - /* Is it a synthesized method that needs to be synthesized? */ if (TREE_CODE (decl) == FUNCTION_DECL && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl) diff --git a/gnu/gcc/gcc/output.h b/gnu/gcc/gcc/output.h index fda098bc3e6..1d9b837e2d7 100644 --- a/gnu/gcc/gcc/output.h +++ b/gnu/gcc/gcc/output.h @@ -200,9 +200,9 @@ extern void assemble_variable (tree, int, int, int); DONT_OUTPUT_DATA is from assemble_variable. */ extern void align_variable (tree decl, bool dont_output_data); -/* Output something to declare an external symbol to the assembler. - (Most assemblers don't need this, so we normally output nothing.) - Do nothing if DECL is not external. */ +/* Queue for outputing something to declare an external symbol to the + assembler. (Most assemblers don't need this, so we normally output + nothing.) Do nothing if DECL is not external. */ extern void assemble_external (tree); /* Assemble code to leave SIZE bytes of zeros. */ @@ -607,6 +607,10 @@ extern void default_file_start (void); extern void file_end_indicate_exec_stack (void); extern bool default_valid_pointer_mode (enum machine_mode); +extern void default_elf_asm_output_external (FILE *file, tree, + const char *); +extern int maybe_assemble_visibility (tree); + extern int default_address_cost (rtx); /* dbxout helper functions */ diff --git a/gnu/gcc/gcc/toplev.c b/gnu/gcc/gcc/toplev.c index bab1524150b..014a6605a36 100644 --- a/gnu/gcc/gcc/toplev.c +++ b/gnu/gcc/gcc/toplev.c @@ -1078,9 +1078,7 @@ compile_file (void) dw2_output_indirect_constants (); - /* Flush any pending external directives. cgraph did this for - assemble_external calls from the front end, but the RTL - expander can also generate them. */ + /* Flush any pending external directives. */ process_pending_assemble_externals (); /* Attach a special .ident directive to the end of the file to identify diff --git a/gnu/gcc/gcc/varasm.c b/gnu/gcc/gcc/varasm.c index 60a17fcdf2d..d17207121fe 100644 --- a/gnu/gcc/gcc/varasm.c +++ b/gnu/gcc/gcc/varasm.c @@ -126,7 +126,6 @@ static unsigned HOST_WIDE_INT array_size_for_constructor (tree); static unsigned min_align (unsigned, unsigned); static void output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int); static void globalize_decl (tree); -static void maybe_assemble_visibility (tree); #ifdef BSS_SECTION_ASM_OP #ifdef ASM_OUTPUT_BSS static void asm_output_bss (FILE *, tree, const char *, @@ -1957,11 +1956,10 @@ assemble_external (tree decl ATTRIBUTE_UNUSED) if (!DECL_P (decl) || !DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl)) return; - if (flag_unit_at_a_time) - pending_assemble_externals = tree_cons (0, decl, - pending_assemble_externals); - else - assemble_external_real (decl); + /* We want to output external symbols at very last to check if they + are references or not. */ + pending_assemble_externals = tree_cons (0, decl, + pending_assemble_externals); #endif } @@ -5064,13 +5062,18 @@ default_assemble_visibility (tree decl, int vis) /* A helper function to call assemble_visibility when needed for a decl. */ -static void +int maybe_assemble_visibility (tree decl) { enum symbol_visibility vis = DECL_VISIBILITY (decl); if (vis != VISIBILITY_DEFAULT) - targetm.asm_out.visibility (decl, vis); + { + targetm.asm_out.visibility (decl, vis); + return 1; + } + else + return 0; } /* Returns 1 if the target configuration supports defining public symbols @@ -6224,4 +6227,19 @@ output_object_blocks (void) htab_traverse (object_block_htab, output_object_block_htab, NULL); } +/* Emit text to declare externally defined symbols. It is needed to + properly support non-default visibility. */ +void +default_elf_asm_output_external (FILE *file ATTRIBUTE_UNUSED, + tree decl, + const char *name ATTRIBUTE_UNUSED) +{ + /* We output the name if and only if TREE_SYMBOL_REFERENCED is + set in order to avoid putting out names that are never really + used. */ + if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) + && targetm.binds_local_p (decl)) + maybe_assemble_visibility (decl); +} + #include "gt-varasm.h" -- 2.20.1