[PATCH v2] [RFC][ld] Introduce static bundle object support

Eyal Itkin eyal.itkin@gmail.com
Sun Oct 12 15:57:11 GMT 2025


> That said, porting this feature from objcopy to ld needs clear justification.
> If relocatable linking output already requires post-processing by
> objcopy, moving this option to ld provides no benefit.

I agree and I am trying to achieve more than just symbol hiding. If the
conclusion will be that the only remaining value will be symbol hiding, we
could keep using objcopy.

> The relocation resolution provides less value than it might appear. In
> builds using -ffunction-sections (commonly paired with ld
> --gc-sections), most global symbols reside in their own dedicated
> sections such as .text.symname and .data.symname. Since these sections
> have distinct names and are not merged with other sections in -r links
> (even without using ld --unique), any relocation referencing them from
> another function becomes a cross-section reference that cannot be
> resolved.

There are several aspects here, so I'll try to break them down. In the
current suggested draft (with slight fix for one relocation) if we take
one of DPDK's libraries as a test case (librte_eal.a), we can see that
there are 262 function symbols that are not placed in the
eal_exports.map out of which only 9 were left in the finalized binary.
This means 96.5% success rate for the relocation finalization.

I fully agree that when using -ffunction-sections there is no point in
performing finalization for the relocations. The user clearly specified
that their top priority is granularity, and they created a binary that
literally uses the function (symbols) names in the created sections.
Accordingly, providing less impact in this case is acceptable.

> Architecturally, while x86-64 can resolve `R_X86_64_PLT32` to local
> symbols within the same section, this approach fails for many RISC
> architectures (AArch64, Power, RISC-V, etc.) where linkers require
> relocations to generate range extension thunks or perform linker
> relaxation

This is a strong argument, which clarifies the tradeoffs between symbol
hiding and binary granularity. I would argue that some users are willing
to sacrifice their granularity, otherwise the "--whole-archive" flag wouldn't
have been so common in provided pkg-config files (DPDK is again an
example). If, for these users, there would be an ability to merge together
the sections and minimize the cross-section relocations, this would also
improve the overall impact of the finalization itself.

This idea was also brought up by Rafael in
https://groups.google.com/g/generic-abi/c/sT25-xfX9yc/m/1lzc9nCCAQAJ.
As was also phrased by Ali before they encouraged the submission to
GNU ld:
"
What you're doing is something else: You're producing a single relocatable
object that's been finalized so that it provides an entire unit of things.
"
https://groups.google.com/g/generic-abi/c/sT25-xfX9yc/m/1gElX6vZAgAJ

For x86-64, the finalization relocation works pretty well, even without
any section-related adjustment. However, if you are saying that for
other architectures (such as aarch64), this approach will no longer hold,
then my question is what is done for shared objects / ELF executables?

I understand that many users will keep on using the current static archives.
Some of these users even use -ffunction-sections as granularity is a
priority for them. These users might still benefit from symbol visibility
features, and it would be great if some ergonomic solution for them could
be achieved.

That said, there are other users for which using a single binary blob "as-is"
is acceptable (again, --whole-archive). If there is a technical solution that
allows the adjustment of the ET_REL so that this will be accomplished,
while maximizing the relocation finalization, this will maximize the
benefits for both the scoping and exposure metrics. This could be named
"--finalize" as thrown by Ali, or "--static-lib --combine-secs" as mentioned
by Rafael. The naming could be adjusted, yet the goal itself stays the
same.

This "--finalize-locals" draft does not aim to solve all issues. There will
be drawbacks, some relocations might be kept and not finalized, and
some users might prefer not to use this option. This is acceptable.
Symbol visibility (scoping) and exposure are real issues that trouble
users, otherwise the https://github.com/tux3/armerge project wouldn't
have been created in the first place. This might come with a tradeoff,
offered granularity will be degraded or even completely sacrificed. Yet
there seems to be a crowd of users for such an option, and this is
what this patch is trying to aim for.

On Sun, Oct 12, 2025 at 8:44 AM Fangrui Song <maskray@sourceware.org> wrote:
>
> On Sat, Oct 11, 2025 at 12:15 PM Eyal Itkin <eyal.itkin@gmail.com> wrote:
> >
> > > Discussions on the generic-abi thread mentioned that "static bundle
> > > object" is probably not a good name.
> >
> > I was never good at naming. Any name that will be accepted by this forum
> > is more than fine by me. Please note this anyway only applies at the code
> > and testing level, as the user-facing CLI flag doesn't mention this name.
>
> If STB_LOCAL conversion for hidden visibility is the only effect, I
> would suggest ld --localize-hidden, similar to objcopy
> --localize-hidden.
> (If we ever introduce --no-localize-hidden , we should ensure an error
> when --no-localize-hidden is used together with non-relocatable links
> (-no-pie, -pie, -shared).)
>
> That said, porting this feature from objcopy to ld needs clear justification.
> If relocatable linking output already requires post-processing by
> objcopy, moving this option to ld provides no benefit.
>
> > > The main idea of the ld -r modifier, if I understand correctly, is to
> > > constrain symbol bindings based on visibility.
> >
> > As mentioned in the thread you linked to, and in my technical paper that
> > started said thread, there are two goals for this effort:
> > 1. As in the shared-library case, apply symbol visibility so to hide internal
> > library functions by converting them to STB_LOCAL.
> > 2. Allow the ability to strip symbols of internal functions so to avoid exposing
> > them at the binary level.
> >
> > The "strip" utility will not be able to strip said symbols as long as they
> > are tied to a relocation, hence the motivation to resolve said relocations.
> > Again, as is done in shared objects.
> >
> > I am aware of the limitations for such relocation resolution, hence the
> > code-level check that skip it for cross-section relocations (as was also
> > added to the testsuite) and which were added following your comment
> > on the thread. It is possible that I indeed missed some code-level checks
> > to enforce some of the constraints you mentioned as I am new to this
> > code base. As is mentioned at the commit title (RFC) I will appreciate
> > any feedback and assistance in implementing my suggestion, as this
> > current revision is still only a draft.
>
> The relocation resolution provides less value than it might appear. In
> builds using -ffunction-sections (commonly paired with ld
> --gc-sections), most global symbols reside in their own dedicated
> sections such as .text.symname and .data.symname. Since these sections
> have distinct names and are not merged with other sections in -r links
> (even without using ld --unique), any relocation referencing them from
> another function becomes a cross-section reference that cannot be
> resolved.
>
> objcopy --discard-all or --strip-unneeded does not discard the
> referenced targets.
>
> Architecturally, while x86-64 can resolve `R_X86_64_PLT32` to local
> symbols within the same section, this approach fails for many RISC
> architectures (AArch64, Power, RISC-V, etc.) where linkers require
> relocations to generate range extension thunks or perform linker
> relaxation
>
> > > Note that ld -r combines sections with the same name, which degrades
> > > section garbage collection
> >
> > The flag that is being introduced by this commit is the --finalize-locals
> > flag, which is added on top of "ld -r" yet does not restrict ld (or the user)
> > from adding additional flags as they see fit. In the testsuite there is
> > an example also with ffunction-sections. Hence, user are free to use
> > the --unique flag, unless I'm missing some restriction that it imposes
> > on the design or implementation.
> >
> > >> Many scenarios prevent relocation resolution:
> > I am aware of that, yet many of the scenarios mentioned are also less
> > relevant for the case at hand (internal function calls). The goal is a
> > best effort approach for removing the internal function names at the
> > code level, the suggestion is not aiming to be a silver bullet that will
> > handle all cases.
> >
> > Given the positive overall notion in the generic-abi thread in favor of
> > submitting this proposal as a patch to GNU ld, I indeed adjusted my
> > draft and submitted said patch. I will gladly adjust whatever needed
> > in the patch so to polish this suggested feature, and will more than
> > appreciate feedback from maintainers who are more familiar with
> > the code base than I am.
>
> I want to clarify the feedback from the generic-abi thread:
> The overall assessment is that this proposal doesn't justify a new
> e_type. However, a few messages recognize there might be room for
> ergonomic improvement worth pursuing within tooling.
>
> I second https://groups.google.com/g/generic-abi/c/sT25-xfX9yc/m/NRo09GQcAwAJ
> Cary's suggestion of
> preserving the notion of individual compilation units and the
> granularity of the archive library format.
> This requires more thoughts about modifying or designing an archive format.
>
> Merging compilation units has some undesired properties:
>
> * Requiring ld --gc-sections to discard unneeded code/data
> * Losing diagnostics that pointing to individual .o files
>
> (
> gcc -c -g a.c b.c
> ld.bfd -r --unique a.o b.o  # combines .debug_info sections.
> .debug_info is specified by the internal linker script, therefore not
> orphan
> ld.bfd -r --unique='*' a.o b.o  # separate .debug_info sections
> )
>
> > On Sat, Oct 11, 2025 at 9:13 PM Fangrui Song <maskray@sourceware.org> wrote:
> > >
> > > On Fri, Oct 10, 2025 at 5:24 AM Eyal Itkin <eyal.itkin@gmail.com> wrote:
> > > >
> > > > Note: This patch is a draft for review.
> > > >
> > > > Introduce a new "Static Bundle Object" which is a
> > > > relocatable object that supports symbol visibility
> > > > and finalization of local relocations. This format
> > > > is aimed to be incorporated within static archives
> > > > so to replace the current static archives of plain
> > > > object code files that are used to form static
> > > > libraries.
> > > >
> > > > The full discussion about the format is available in the
> > > > generic-abi group that is responsible for the ELF standard:
> > > > https://groups.google.com/g/generic-abi/c/sT25-xfX9yc
> > > >
> > > > Some questions I had about the process itself:
> > > > 1. The patch is architecture dependent given that
> > > > relocations support is found in both bfd/elflink.c AND
> > > > in some arch-specific files (such as bfd/elf64-x86-64.c).
> > > > Hence, what is the standard way for marking some archs as
> > > > not yet supported? And what is the recommended process for
> > > > adding said support (especially given need to test it)?
> > > >
> > > > Signed-off-by: Eyal Itkin <eyal.itkin@gmail.com>
> > >
> > > Discussions on the generic-abi thread mentioned that "static bundle
> > > object" is probably not a good name.
> > >
> > > The main idea of the ld -r modifier, if I understand correctly, is to
> > > constrain symbol bindings based on visibility.
> > > In my opinion, resolving relocations isn't useful for this purpose, as
> > > I mentioned in my comment at
> > > https://groups.google.com/g/generic-abi/c/sT25-xfX9yc/m/bE-MMmxTAQAJ
> > >
> > >     Only a limited set of relocations can actually be resolved in
> > > relocatable files.
> > >     Specifically, this applies to relocations following the (S-P+A)
> > > formula where S refers to a non-ifunc local symbol in the same section
> > > as P.
> > >     This behavior mirrors assembler fixup resolution
> > > (https://maskray.me/blog/2025-03-16-relocation-generation-in-assemblers
> > > ):
> > >
> > >     > Fixup resolution depends on the fixup type:
> > >     >
> > >     > - PC-relative fixups that describe the symbol itself (the
> > > relocation operation looks like S - P + A) resolve to a constant if
> > > sym_a is a non-ifunc local symbol defined in the current section.
> > >     > - relocation_specifier(S + A) style fixups resolve when S refers
> > > to an absolute symbol.
> > >     > - Other fixups, including TLS and GOT related ones, remain unresolved.
> > >
> > >     Many scenarios prevent relocation resolution:
> > >
> > >     - Cross-section symbol references
> > >     - Symbols with STB_WEAK or STB_GLOBAL binding (due to potential
> > > symbol interposition in shared libraries and linker script symbol
> > > assignments)
> > >     - TLS or GOT-related relocations
> > >     - Relocations potentially requiring PLT entries or range-extension thunks
> > >
> > > I've analyzed the following assembly with a patched ld-new
> > >
> > > .hidden ext
> > > .hidden hid
> > > .global _start, hid
> > > _start:
> > > hid:
> > > .L1:
> > >   call ext
> > >   call hid
> > >   #mov hid@gotpcrel(%rip), %rax
> > >
> > > .section .text,"ax",@progbits,unique,1
> > >   .long .L1 - .
> > >   call .L1
> > >
> > > .section .data,"aw"
> > >   .long .L1 - .
> > >
> > > % ~/Dev/binutils-gdb/out/debug/ld/ld-new -r a.o --finalize-locals -o
> > > a.fo && readelf -W -r a.fo
> > >
> > > Relocation section '.rela.text' at offset 0xf8 contains 2 entries:
> > >     Offset             Info             Type               Symbol's
> > > Value  Symbol's Name + Addend
> > > 000000000000000a  0000000100000002 R_X86_64_PC32
> > > 0000000000000000 .text + 0
> > > 000000000000000f  0000000100000004 R_X86_64_PLT32
> > > 0000000000000000 .text - 4
> > >
> > > Relocation section '.rela.data' at offset 0x128 contains 1 entry:
> > >     Offset             Info             Type               Symbol's
> > > Value  Symbol's Name + Addend
> > > 0000000000000000  0000000100000002 R_X86_64_PC32
> > > 0000000000000000 .text + 0
> > >
> > > Two relocations are resolved, which is not useful.
> > > ld-new would crash if I add this GOT-related relocation
> > >
> > >   mov hid@gotpcrel(%rip), %rax
> > >
> > > ---
> > >
> > > Note that ld -r combines sections with the same name, which degrades
> > > section garbage collection
> > > (shameless plug https://maskray.me/blog/2021-02-28-linker-garbage-collection )
> > > You can use --unique to preserve multiple sections of the same name,
> > > at least for sections from different .o files. However, this doesn't
> > > help with the .text sections in this example.


More information about the Binutils mailing list