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

Jan Beulich via Binutils-cvs <[email protected]>
Newsgroups gmane.comp.gnu.binutils.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=695e1cb7f1e6158e113f6022a57083b82ff5ef54

commit 695e1cb7f1e6158e113f6022a57083b82ff5ef54
Author: Jan Beulich <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.