From 0ea93af841c0f51371405bdce42755fef1dba9fb Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Wed, 24 Jun 2026 08:09:56 +0800
Subject: [PATCH] gas/ELF: Allow local symbol with hidden visibility

In the source code extracted from glibc:

extern void _dl_sysinfo_int80 (void)
  __attribute__ ((visibility ("hidden")));

asm (".text\n\t"
     ".type _dl_sysinfo_int80,@function\n"
     "_dl_sysinfo_int80:\n\t"
     "int $0x80;\n\t"
     "ret");

uintptr_t
foo ()
{
  return (uintptr_t) _dl_sysinfo_int80;
}

_dl_sysinfo_int80 is a local function, but it is defined in an asm
statement.  Since it is referenced in C, it is declared as hidden,
which leads to an assembler warning:

Warning: local symbol `_dl_sysinfo_int80' has non-default visibility

Symbol binding and visiblity are orthogonal.  One is for link-editing,
the other for runtime linking.  In principle, all combinations are "okay"
(if questionable), and have obvious implementations.  But it's only that
specific combination STB_LOCAL+STV_PROTECTED that is explicitely made
ill-formed in the spec (despite it being also obviously implementable).
Warning on that combination can be done on the grounds of following the
spec.  But no other combination is so spelled out, so there's no basis
for trying to disallow them.

Update elf_adjust_symtab to avoid such warning.

binutils/

	PR gas/34312
	* testsuite/binutils-all/localize-hidden-1.l: Adjusted.

gas/

	PR gas/34312
	* config/obj-elf.c (elf_adjust_symtab): Allow local symbol with
	hidden visibility.
	* testsuite/gas/elf/visibility.l: Adjusted.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
 binutils/testsuite/binutils-all/localize-hidden-1.l | 1 -
 gas/config/obj-elf.c                                | 5 ++++-
 gas/testsuite/gas/elf/visibility.l                  | 1 -
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/binutils/testsuite/binutils-all/localize-hidden-1.l b/binutils/testsuite/binutils-all/localize-hidden-1.l
index 2ae5910037b..edba3aad845 100644
--- a/binutils/testsuite/binutils-all/localize-hidden-1.l
+++ b/binutils/testsuite/binutils-all/localize-hidden-1.l
@@ -1,4 +1,3 @@
 [^:]*: Assembler messages:
-[^:]*: Warning: local symbol .Lhidden. has non-default visibility
 [^:]*: Warning: local symbol .Linternal. has non-default visibility
 [^:]*: Warning: local symbol .Lprotected. has non-default visibility
diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index 6850cab1902..862f505760a 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -2756,7 +2756,10 @@ elf_adjust_symtab (void)
 	  const asymbol *bfdsym = symbol_get_bfdsym (symp);
 	  elf_symbol_type *elfsym = elf_symbol_from (bfdsym);
 
-	  if (ELF_ST_VISIBILITY (elfsym->internal_elf_sym.st_other)
+	  /* Allow local symbol with hidden visibility:
+	     https://sourceware.org/bugzilla/show_bug.cgi?id=34312 */
+	  if ((ELF_ST_VISIBILITY (elfsym->internal_elf_sym.st_other)
+	       & ~STV_HIDDEN) != 0
 	      && !(bfdsym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)))
 	    as_warn (_("local symbol `%s' has non-default visibility"),
 		     S_GET_NAME (symp));
diff --git a/gas/testsuite/gas/elf/visibility.l b/gas/testsuite/gas/elf/visibility.l
index 4abd55d9ff5..1f7fdf9a1d3 100644
--- a/gas/testsuite/gas/elf/visibility.l
+++ b/gas/testsuite/gas/elf/visibility.l
@@ -4,5 +4,4 @@
 [^:]*:21: Warning: visibility of .ge. is already .hidden.
 [^:]*:26: Warning: visibility of .we. is already .hidden.
 [^:]*: Warning: local symbol .li. has non-default visibility
-[^:]*: Warning: local symbol .lh. has non-default visibility
 [^:]*: Warning: local symbol .lp. has non-default visibility
-- 
2.54.0

