Bug 31000 - objcopy: add support for changing ELF symbol visibility
Summary: objcopy: add support for changing ELF symbol visibility
Status: NEW
Alias: None
Product: binutils
Classification: Unclassified
Component: binutils (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-10-26 05:24 UTC by Fangrui Song
Modified: 2024-02-28 14:08 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Fangrui Song 2023-10-26 05:24:25 UTC
Recently I have been dealing with a benign multiple definition related to compiler-rt/lib/builtins and rust-lang/compiler-builtins.
I need a workaround to convert certain symbols with hidden visibility to default visibility.
(If you are curious, see https://discourse.llvm.org/t/relocatable-file-definitions-shared-with-dso/74391 related to an improved linker error --no-allow-shlib-undefined)

It appears that objcopy does not provide a direct way to set symbol visibility, but I have found a workaround:

    objcopy --strip-symbol __udivmodti4 --add-symbol __udivmodti4=.text.__udivmodti4:0,weak udivmodti4.c.o

Running this command on an archive will add __udivmodti4 to every archive member, which is not desired. So, I needed to determine which archive member defines __udivmodti4. I ended up implementing something like this in Bazel:

    """$(AR) x --output=$(@D)/lib $(OUTS)
    for o in $(@D)/lib/*.o; do
      $(NM) -gU $$o | grep -qw __udivmodti4 && $(OBJCOPY) --strip-symbol __udivmodti4 --add-symbol __udivmodti4=.text.__udivmodti4:0,weak $$o
    done
    $(AR) r $(OUTS) $(@D)/lib/*.o
    rm -rf $(@D)/lib"""

This is cumbersome.

Suppose you want to convert a symbol from default visibility to hidden visibility. Unfortunately, I couldn't find a straightforward way to do it.
However, llvm-objcopy provides two extension:

    # objcopy --strip-symbol __udivmodti4 --add-symbol __udivmodti4=.text.__udivmodti4:0,weak,hidden udivmodti4.c.o # unrecognized symbol flag `hidden'
    llvm-objcopy --strip-symbol __udivmodti4 --add-symbol __udivmodti4=.text.__udivmodti4:0,weak,hidden udivmodti4.c.o
    llvm-objcopy --strip-symbol __udivmodti4 --add-symbol __udivmodti4=.text.__udivmodti4:0,weak --new-symbol-visibility=hidden udivmodti4.c.o

https://llvm.org/docs/CommandGuide/llvm-objcopy.html#cmdoption-llvm-objcopy-new-symbol-visibility

--new-symbol-visibility also affects `_binary_*_{start,end,size}` symbols created by
llvm-objcopy --new-symbol-visibility hidden -I binary -B i386:x86-64 a.txt a.o

This feature request tracks these possible extensions:

* 'hidden' in --add-symbol
* --new-symbol-visibility=hidden
* An option like --set-symbol-flags that can operate on an existing symbol
Comment 1 Fangrui Song 2024-02-09 06:53:32 UTC
On the llvm-objcopy side, someone proposes --set-symbol-visibility: https://github.com/llvm/llvm-project/pull/80872
Comment 2 Fangrui Song 2024-02-22 04:10:27 UTC
(In reply to Fangrui Song from comment #1)
> On the llvm-objcopy side, someone proposes --set-symbol-visibility:
> https://github.com/llvm/llvm-project/pull/80872

The proposal looks like:

.. option:: --set-symbol-visibility <symbol>=<visibility_type>

 Change the visibility of a symbol to the specified type.

.. option:: --set-symbols-visibility <filename>=<visibility_type>

 Reads a list of symbols from <filename> and changes their visibility to the
 specified type. Visibility types: default, internal, hidden, protected.

for ELF targets.
Comment 3 Nick Clifton 2024-02-28 14:08:06 UTC
(In reply to Fangrui Song from comment #2)

> .. option:: --set-symbols-visibility <filename>=<visibility_type>
> 
>  Reads a list of symbols from <filename> and changes their visibility to the
>  specified type. Visibility types: default, internal, hidden, protected.

Given the support for "@<file>" for reading in a list of command line options,
is the format above really necessary ?

Using a file containing lots of:

 --set-symbol-visibility <symbol>=<vis-type>

entries might require a bigger file, but it would also be more flexible,
allowing for multiple types of visibility to be set, along with other
options as well.