[PATCH] x86: Always treat protected symbols as local
Fangrui Song
i@maskray.me
Tue Aug 12 05:54:41 GMT 2025
On Mon, Aug 11, 2025 at 12:50 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> Since linker never generates dynamic relocation for protected symbol in:
>
> __attribute__((visibility("protected"))) int my_data;
>
> int *
> func (void)
> {
> return &my_data;
> }
>
> we should always treat protected symbols as local.
>
> bfd/
>
> PR ld/33260
> * elfxx-x86.h (COPY_INPUT_RELOC_P): Always treat protected symbols
> as local.
>
> ld/
>
> PR ld/33260
> * testsuite/ld-i386/i386-export-class.rd: Updated.
> * testsuite/ld-i386/i386-export-class.xd: Likewise.
> * testsuite/ld-i386/i386.exp: Run pr33260-2.
> * testsuite/ld-i386/pr33260-2.d: New file.
> * testsuite/ld-i386/pr33260-2.s: Likewise.
> * testsuite/ld-i386/pr33260.d: Remove "-z indirect-extern-access".
> * testsuite/ld-x86-64/pr33260-x32.d: Likewise.
> * testsuite/ld-x86-64/pr33260.d: Likewise.
> * testsuite/ld-x86-64/pr33260-2-x32.d: New file.
> * testsuite/ld-x86-64/pr33260-2.d: Likewise.
> * testsuite/ld-x86-64/pr33260-2.s: Likewise.
> * testsuite/ld-x86-64/x86-64-64-export-class.rd: Updated.
> * testsuite/ld-x86-64/x86-64-x32-export-class.rd: Likewise.
> * testsuite/ld-x86-64/x86-64.exp: Run pr33260-2 and
> pr33260-2-x32.
>
> Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> ---
> bfd/elfxx-x86.h | 5 ++--
> ld/testsuite/ld-i386/i386-export-class.rd | 6 ++--
> ld/testsuite/ld-i386/i386-export-class.xd | 6 ++--
> ld/testsuite/ld-i386/i386.exp | 1 +
> ld/testsuite/ld-i386/pr33260-2.d | 6 ++++
> ld/testsuite/ld-i386/pr33260-2.s | 30 +++++++++++++++++++
> ld/testsuite/ld-i386/pr33260.d | 2 +-
> ld/testsuite/ld-x86-64/pr33260-2-x32.d | 6 ++++
> ld/testsuite/ld-x86-64/pr33260-2.d | 6 ++++
> ld/testsuite/ld-x86-64/pr33260-2.s | 19 ++++++++++++
> ld/testsuite/ld-x86-64/pr33260-x32.d | 2 +-
> ld/testsuite/ld-x86-64/pr33260.d | 2 +-
> .../ld-x86-64/x86-64-64-export-class.rd | 6 ++--
> .../ld-x86-64/x86-64-x32-export-class.rd | 6 ++--
> ld/testsuite/ld-x86-64/x86-64.exp | 2 ++
> 15 files changed, 87 insertions(+), 18 deletions(-)
> create mode 100644 ld/testsuite/ld-i386/pr33260-2.d
> create mode 100644 ld/testsuite/ld-i386/pr33260-2.s
> create mode 100644 ld/testsuite/ld-x86-64/pr33260-2-x32.d
> create mode 100644 ld/testsuite/ld-x86-64/pr33260-2.d
> create mode 100644 ld/testsuite/ld-x86-64/pr33260-2.s
>
> diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
> index 05c416fdf26..f6ee6a65356 100644
> --- a/bfd/elfxx-x86.h
> +++ b/bfd/elfxx-x86.h
> @@ -225,15 +225,14 @@
>
> /* TRUE if this input relocation should be copied to output. H->dynindx
> may be -1 if this symbol was marked to become local. STV_PROTECTED
> - symbols with indirect external access are local. */
> + symbols are local. */
> #define COPY_INPUT_RELOC_P(IS_X86_64, INFO, H, R_TYPE) \
> ((H) != NULL \
> && (H)->dynindx != -1 \
> && (X86_PCREL_TYPE_P (IS_X86_64, R_TYPE) \
> || !(bfd_link_executable (INFO) \
> || SYMBOLIC_BIND ((INFO), (H)) \
> - || ((INFO)->indirect_extern_access > 0 \
> - && ELF_ST_VISIBILITY ((H)->other) == STV_PROTECTED)) \
> + || ELF_ST_VISIBILITY ((H)->other) == STV_PROTECTED) \
> || !(H)->def_regular))
>
> /* TRUE if this is actually a static link, or it is a -Bsymbolic link
> diff --git a/ld/testsuite/ld-i386/i386-export-class.rd b/ld/testsuite/ld-i386/i386-export-class.rd
> index d7beadef2c4..7ec0825ee5b 100644
> --- a/ld/testsuite/ld-i386/i386-export-class.rd
> +++ b/ld/testsuite/ld-i386/i386-export-class.rd
> @@ -1,11 +1,11 @@
> Relocation section '\.rel\.dyn' at offset 0x[0-9a-f]+ contains [0-9]+ entries:
> * Offset * Info * Type * Sym\. *Value * Sym\. * Name
> +12340000 00000008 R_386_RELATIVE *
> 12340010 00000008 R_386_RELATIVE *
> 12340020 00000008 R_386_RELATIVE *
> +12340040 00000008 R_386_RELATIVE *
> +12340050 00000008 R_386_RELATIVE *
> 12340060 00000008 R_386_RELATIVE *
> 12340070 00000008 R_386_RELATIVE *
> 12340080 00000008 R_386_RELATIVE *
> 12340090 00000008 R_386_RELATIVE *
> -12340000 [0-9a-f]+01 R_386_32 123400a0 protected_baz
> -12340040 [0-9a-f]+01 R_386_32 123400a0 protected_foo
> -12340050 [0-9a-f]+01 R_386_32 123400a0 protected_bar
> diff --git a/ld/testsuite/ld-i386/i386-export-class.xd b/ld/testsuite/ld-i386/i386-export-class.xd
> index a797f206940..31f011f8136 100644
> --- a/ld/testsuite/ld-i386/i386-export-class.xd
> +++ b/ld/testsuite/ld-i386/i386-export-class.xd
> @@ -1,10 +1,10 @@
> Hex dump of section '\.data':
> - 0x12340000 00000000 00000000 00000000 00000000 .*
> + 0x12340000 a0003412 00000000 00000000 00000000 .*
> 0x12340010 a0003412 00000000 00000000 00000000 .*
> 0x12340020 a0003412 00000000 00000000 00000000 .*
> 0x12340030 00000000 00000000 00000000 00000000 .*
> - 0x12340040 00000000 00000000 00000000 00000000 .*
> - 0x12340050 00000000 00000000 00000000 00000000 .*
> + 0x12340040 a0003412 00000000 00000000 00000000 .*
> + 0x12340050 a0003412 00000000 00000000 00000000 .*
> 0x12340060 a0003412 00000000 00000000 00000000 .*
> 0x12340070 a0003412 00000000 00000000 00000000 .*
> 0x12340080 a0003412 00000000 00000000 00000000 .*
> diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp
> index 0d653e90627..86748b1a494 100644
> --- a/ld/testsuite/ld-i386/i386.exp
> +++ b/ld/testsuite/ld-i386/i386.exp
> @@ -521,6 +521,7 @@ run_dump_test "pr30787"
> run_dump_test "pr31047"
> run_dump_test "pr32191"
> run_dump_test "pr33260"
> +run_dump_test "pr33260-2"
>
> if { !([istarget "i?86-*-linux*"]
> || [istarget "i?86-*-gnu*"]
> diff --git a/ld/testsuite/ld-i386/pr33260-2.d b/ld/testsuite/ld-i386/pr33260-2.d
> new file mode 100644
> index 00000000000..d84442b631b
> --- /dev/null
> +++ b/ld/testsuite/ld-i386/pr33260-2.d
> @@ -0,0 +1,6 @@
> +#source: pr33260-2.s
> +#as: -mrelax-relocations=yes --32
> +#ld: -melf_i386 -shared
> +#readelf: -r --wide
> +
> +There are no relocations in this file.
> diff --git a/ld/testsuite/ld-i386/pr33260-2.s b/ld/testsuite/ld-i386/pr33260-2.s
> new file mode 100644
> index 00000000000..0fcd3888854
> --- /dev/null
> +++ b/ld/testsuite/ld-i386/pr33260-2.s
> @@ -0,0 +1,30 @@
> + .text
> + .p2align 4
> + .globl my_func
> + .type my_func, @function
> +my_func:
> + .cfi_startproc
> + call __x86.get_pc_thunk.ax
> + addl $_GLOBAL_OFFSET_TABLE_, %eax
> + movl my_data@GOT(%eax), %eax
> + ret
> + .cfi_endproc
> + .size my_func, .-my_func
> + .protected my_data
> + .globl my_data
> + .bss
> + .align 4
> + .type my_data, @object
> + .size my_data, 4
> +my_data:
> + .zero 4
> + .section .text.__x86.get_pc_thunk.ax,"axG",@progbits,__x86.get_pc_thunk.ax,comdat
> + .globl __x86.get_pc_thunk.ax
> + .hidden __x86.get_pc_thunk.ax
> + .type __x86.get_pc_thunk.ax, @function
> +__x86.get_pc_thunk.ax:
> + .cfi_startproc
> + movl (%esp), %eax
> + ret
> + .cfi_endproc
> + .section .note.GNU-stack,"",@progbits
> diff --git a/ld/testsuite/ld-i386/pr33260.d b/ld/testsuite/ld-i386/pr33260.d
> index 4b1755d9938..fc05e4ca596 100644
> --- a/ld/testsuite/ld-i386/pr33260.d
> +++ b/ld/testsuite/ld-i386/pr33260.d
> @@ -1,6 +1,6 @@
> #source: pr33260.s
> #as: -mrelax-relocations=yes --32
> -#ld: -melf_i386 -shared -z indirect-extern-access
> +#ld: -melf_i386 -shared
> #readelf: -r --wide
>
> Relocation section '.rel.dyn' at offset 0x[0-9a-f]+ contains 2 entries:
> diff --git a/ld/testsuite/ld-x86-64/pr33260-2-x32.d b/ld/testsuite/ld-x86-64/pr33260-2-x32.d
> new file mode 100644
> index 00000000000..383129a3670
> --- /dev/null
> +++ b/ld/testsuite/ld-x86-64/pr33260-2-x32.d
> @@ -0,0 +1,6 @@
> +#source: pr33260-2.s
> +#as: -mrelax-relocations=yes --x32
> +#ld: -melf32_x86_64 -shared
> +#readelf: -r --wide
> +
> +There are no relocations in this file.
> diff --git a/ld/testsuite/ld-x86-64/pr33260-2.d b/ld/testsuite/ld-x86-64/pr33260-2.d
> new file mode 100644
> index 00000000000..7f237c886fb
> --- /dev/null
> +++ b/ld/testsuite/ld-x86-64/pr33260-2.d
> @@ -0,0 +1,6 @@
> +#source: pr33260-2.s
> +#as: -mrelax-relocations=yes --64
> +#ld: -melf_x86_64 -shared
> +#readelf: -r --wide
> +
> +There are no relocations in this file.
> diff --git a/ld/testsuite/ld-x86-64/pr33260-2.s b/ld/testsuite/ld-x86-64/pr33260-2.s
> new file mode 100644
> index 00000000000..061137d032b
> --- /dev/null
> +++ b/ld/testsuite/ld-x86-64/pr33260-2.s
> @@ -0,0 +1,19 @@
> + .text
> + .p2align 4
> + .globl my_func
> + .type my_func, @function
> +my_func:
> + .cfi_startproc
> + movq my_data@GOTPCREL(%rip), %rax
> + ret
> + .cfi_endproc
> + .size my_func, .-my_func
> + .protected my_data
> + .globl my_data
> + .bss
> + .align 4
> + .type my_data, @object
> + .size my_data, 4
> +my_data:
> + .zero 4
> + .section .note.GNU-stack,"",@progbits
> diff --git a/ld/testsuite/ld-x86-64/pr33260-x32.d b/ld/testsuite/ld-x86-64/pr33260-x32.d
> index d45e42dca3d..42088fbc4e1 100644
> --- a/ld/testsuite/ld-x86-64/pr33260-x32.d
> +++ b/ld/testsuite/ld-x86-64/pr33260-x32.d
> @@ -1,6 +1,6 @@
> #source: pr33260.s
> #as: -mrelax-relocations=yes --x32
> -#ld: -melf32_x86_64 -shared -z indirect-extern-access
> +#ld: -melf32_x86_64 -shared
> #readelf: -r --wide
>
> Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 2 entries:
> diff --git a/ld/testsuite/ld-x86-64/pr33260.d b/ld/testsuite/ld-x86-64/pr33260.d
> index d98c1658fa1..18b5472a03f 100644
> --- a/ld/testsuite/ld-x86-64/pr33260.d
> +++ b/ld/testsuite/ld-x86-64/pr33260.d
> @@ -1,6 +1,6 @@
> #source: pr33260.s
> #as: -mrelax-relocations=yes --64 -defsym __x86_64__=1
> -#ld: -melf_x86_64 -shared -z indirect-extern-access
> +#ld: -melf_x86_64 -shared
> #readelf: -r --wide
>
> Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 2 entries:
> diff --git a/ld/testsuite/ld-x86-64/x86-64-64-export-class.rd b/ld/testsuite/ld-x86-64/x86-64-64-export-class.rd
> index 308e307c94b..4a0bfa1cc10 100644
> --- a/ld/testsuite/ld-x86-64/x86-64-64-export-class.rd
> +++ b/ld/testsuite/ld-x86-64/x86-64-64-export-class.rd
> @@ -1,11 +1,11 @@
> Relocation section '\.rela\.dyn' at offset 0x[0-9a-f]+ contains [0-9]+ entries:
> * Offset * Info * Type * Sym\. *Value * Sym\. * Name * \+ * Addend
> +000012340000 000000000008 R_X86_64_RELATIVE 123400a0
> 000012340010 000000000008 R_X86_64_RELATIVE 123400a0
> 000012340020 000000000008 R_X86_64_RELATIVE 123400a0
> +000012340040 000000000008 R_X86_64_RELATIVE 123400a0
> +000012340050 000000000008 R_X86_64_RELATIVE 123400a0
> 000012340060 000000000008 R_X86_64_RELATIVE 123400a0
> 000012340070 000000000008 R_X86_64_RELATIVE 123400a0
> 000012340080 000000000008 R_X86_64_RELATIVE 123400a0
> 000012340090 000000000008 R_X86_64_RELATIVE 123400a0
> -000012340000 [0-9a-f]+00000001 R_X86_64_64 00000000123400a0 protected_baz \+ 0
> -000012340040 [0-9a-f]+00000001 R_X86_64_64 00000000123400a0 protected_foo \+ 0
> -000012340050 [0-9a-f]+00000001 R_X86_64_64 00000000123400a0 protected_bar \+ 0
> diff --git a/ld/testsuite/ld-x86-64/x86-64-x32-export-class.rd b/ld/testsuite/ld-x86-64/x86-64-x32-export-class.rd
> index 4ea93bacfcc..5018229f2b5 100644
> --- a/ld/testsuite/ld-x86-64/x86-64-x32-export-class.rd
> +++ b/ld/testsuite/ld-x86-64/x86-64-x32-export-class.rd
> @@ -1,11 +1,11 @@
> Relocation section '\.rela\.dyn' at offset 0x[0-9a-f]+ contains [0-9]+ entries:
> * Offset * Info * Type * Sym\. *Value * Sym\. * Name * \+ * Addend
> +12340000 00000008 R_X86_64_RELATIVE 123400a0
> 12340010 00000008 R_X86_64_RELATIVE 123400a0
> 12340020 00000008 R_X86_64_RELATIVE 123400a0
> +12340040 00000008 R_X86_64_RELATIVE 123400a0
> +12340050 00000008 R_X86_64_RELATIVE 123400a0
> 12340060 00000008 R_X86_64_RELATIVE 123400a0
> 12340070 00000008 R_X86_64_RELATIVE 123400a0
> 12340080 00000008 R_X86_64_RELATIVE 123400a0
> 12340090 00000008 R_X86_64_RELATIVE 123400a0
> -12340000 [0-9a-f]+0a R_X86_64_32 123400a0 protected_baz \+ 0
> -12340040 [0-9a-f]+0a R_X86_64_32 123400a0 protected_foo \+ 0
> -12340050 [0-9a-f]+0a R_X86_64_32 123400a0 protected_bar \+ 0
> diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
> index f3fdf023cb2..6b86bc3d018 100644
> --- a/ld/testsuite/ld-x86-64/x86-64.exp
> +++ b/ld/testsuite/ld-x86-64/x86-64.exp
> @@ -566,6 +566,8 @@ run_dump_test "pr32591-4-x32"
> run_dump_test "pr32809"
> run_dump_test "pr33260"
> run_dump_test "pr33260-x32"
> +run_dump_test "pr33260-2"
> +run_dump_test "pr33260-2-x32"
>
> if { ![skip_sframe_tests] } {
> run_dump_test "sframe-simple-1"
> --
> 2.50.1
>
The proposed change aligns the x86 behavior with non-x86 ports and
other linkers (gold, lld, mold), which is a positive step.
This might be similar to
https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=d19a265487eda186b6977d9d15648cda9fad3298
("x86: Make protected symbols local for -shared")
in spirit.
While the condition appears complex, the patch is moving in the right direction.
The core concept is whether a symbol is preemptible. Other linkers
like LLD and mold use a single, clear property for this,
Symbol::isPreemptible or is_imported.
A protected visibility symbol isn't preemptible.
Good progress has been made toward fixing protected symbols for GCC
and GNU ld :) which already work well with Clang and non-x86 GCC/GNU
ld ports.
https://maskray.me/blog/2021-01-09-copy-relocations-canonical-plt-entries-and-protected#reflection-on-protected-data-symbols-and-copy-relocations
More information about the Binutils
mailing list