[binutils-gdb] gas/ELF: restrict visibility changes

Jan Beulich jbeulich@sourceware.org
Fri May 8 09:47:11 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=695e1cb7f1e6158e113f6022a57083b82ff5ef54

commit 695e1cb7f1e6158e113f6022a57083b82ff5ef54
Author: Jan Beulich <jbeulich@suse.com>
Date:   Fri May 8 11:44:09 2026 +0200

    gas/ELF: restrict visibility changes
    
    Since the spec mandates that the most restricting visibility ought to
    propagate when linking, the same rule should apply when assembling.

Diff:
---
 gas/config/obj-elf.c               | 21 ++++++++++++---------
 gas/testsuite/gas/elf/elf.exp      |  1 +
 gas/testsuite/gas/elf/pseudo.l     |  1 +
 gas/testsuite/gas/elf/visibility.d | 12 ++++++++++++
 gas/testsuite/gas/elf/visibility.l |  5 +++++
 gas/testsuite/gas/elf/visibility.s | 28 ++++++++++++++++++++++++++++
 6 files changed, 59 insertions(+), 9 deletions(-)

diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index f884e577554..06216906420 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -404,21 +404,24 @@ static void
 obj_elf_visibility (int visibility)
 {
   int c;
-  symbolS *symbolP;
-  asymbol *bfdsym;
-  elf_symbol_type *elfsym;
 
   do
     {
-      symbolP = get_sym_from_input_line_and_check ();
-
-      bfdsym = symbol_get_bfdsym (symbolP);
-      elfsym = elf_symbol_from (bfdsym);
+      symbolS *symbolP = get_sym_from_input_line_and_check ();
+      const asymbol *bfdsym = symbol_get_bfdsym (symbolP);
+      elf_symbol_type *elfsym = elf_symbol_from (bfdsym);
+      int current = ELF_ST_VISIBILITY (elfsym->internal_elf_sym.st_other);
 
       gas_assert (elfsym);
 
-      elfsym->internal_elf_sym.st_other &= ~3;
-      elfsym->internal_elf_sym.st_other |= visibility;
+      if (!current || visibility <= current)
+	{
+	  elfsym->internal_elf_sym.st_other &= ~ELF_ST_VISIBILITY (~0);
+	  elfsym->internal_elf_sym.st_other |= visibility;
+	}
+      else
+	as_warn (_("visibility of `%s' is already `%s'"), S_GET_NAME (symbolP),
+		 current == STV_HIDDEN ? "hidden" : "internal");
 
       c = *input_line_pointer;
       if (c == ',')
diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp
index cf983057bf6..2232e2d58d9 100644
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -237,6 +237,7 @@ if { [is_elf_format] } then {
 	# The alpha port uses .set for state, e.g. nomacro.
 	run_dump_test "symtab"
     }
+    run_dump_test "visibility"
     run_dump_test "symver"
     run_dump_test "pr21661"
     run_dump_test "pr14891"
diff --git a/gas/testsuite/gas/elf/pseudo.l b/gas/testsuite/gas/elf/pseudo.l
index 605f5b889b5..667d6205d49 100644
--- a/gas/testsuite/gas/elf/pseudo.l
+++ b/gas/testsuite/gas/elf/pseudo.l
@@ -4,6 +4,7 @@
 [^:]*:6: Error: Missing symbol name in directive
 [^:]*:8: Error: Missing symbol name in directive
 [^:]*:10: Error: Missing symbol name in directive
+[^:]*:10: Warning: visibility of .* is already .internal.
 [^:]*:12: Error: Missing symbol name in directive
 [^:]*:14: Error: Missing symbol name in directive
 [^:]*:14: Error: expected comma after name in .symver
diff --git a/gas/testsuite/gas/elf/visibility.d b/gas/testsuite/gas/elf/visibility.d
new file mode 100644
index 00000000000..89c977dd9ec
--- /dev/null
+++ b/gas/testsuite/gas/elf/visibility.d
@@ -0,0 +1,12 @@
+#name: diagnostics for visibility directives
+#readelf: -s -W
+#warning_output: visibility.l
+#target: [supports_gnu_unique]
+
+#...
+ +[0-9]+: +0+ +0 +(NOTYPE|OBJECT) +GLOBAL +INTERNAL +[1-9] +gd
+ +[0-9]+: +0+1 +0 +(NOTYPE|OBJECT) +WEAK +INTERNAL +[1-9] +wd
+ +[0-9]+: +0+2 +0 +OBJECT +UNIQUE +HIDDEN +[1-9] +gu
+ +[0-9]+: +0+ +0 +(NOTYPE|OBJECT) +GLOBAL +INTERNAL +UND +ge
+ +[0-9]+: +0+ +0 +(NOTYPE|OBJECT) +WEAK +HIDDEN +UND +we
+#pass
diff --git a/gas/testsuite/gas/elf/visibility.l b/gas/testsuite/gas/elf/visibility.l
new file mode 100644
index 00000000000..db2f858e8f4
--- /dev/null
+++ b/gas/testsuite/gas/elf/visibility.l
@@ -0,0 +1,5 @@
+[^:]*: Assembler messages:
+[^:]*:4: Warning: visibility of .gd. is already .internal.
+[^:]*:5: Warning: visibility of .gd. is already .internal.
+[^:]*:21: Warning: visibility of .ge. is already .hidden.
+[^:]*:26: Warning: visibility of .we. is already .hidden.
diff --git a/gas/testsuite/gas/elf/visibility.s b/gas/testsuite/gas/elf/visibility.s
new file mode 100644
index 00000000000..01ced4a5888
--- /dev/null
+++ b/gas/testsuite/gas/elf/visibility.s
@@ -0,0 +1,28 @@
+	.data
+	.global gd
+	.internal gd
+	.hidden gd
+	.protected gd
+gd:	.dc.b 0
+
+	.weak wd
+	.protected wd
+	.hidden wd
+	.internal wd
+wd:	.dc.b 0
+
+	.type gu, %gnu_unique_object
+	.hidden gu
+	.hidden gu
+gu:	.dc.b 0
+
+	.global ge
+	.hidden ge
+	.protected ge
+	.internal ge
+
+	.weak we
+	.hidden we
+	.protected we
+	.p2align 3
+	.dc.a we


More information about the Binutils-cvs mailing list