Proposal for a new e_type value to be used for static libraries

57 views
Skip to first unread message

Eyal Itkin

unread,
Sep 25, 2025, 10:24:28 PM (5 days ago) Sep 25
to Generic System V Application Binary Interface
Greetings,

I have prepared the following proposal to extend the ELF standard by adding a new e_type value: ET_STAT.

The value will be used by a new proposed format (Static Bundle Object) that hopefully will be used to represent static libraries, and will replace the currently used ".a" archive of ET_REL object code (.o) files. The end goal is to overcome the limitations in the ".a" static archive format that is currently used for static libraries, and bring the static libraries format closer to the ET_DYN e_type used for dynamic libraries.

Link to the technical white paper with the proposal:
* File name: "2025-09 - Static Bundle Object - Proposal for a New ELF Type for Static Library Linking.pdf"

The paper also refers to a proof-of-concept implementation of the suggested format on top of GNU's ld, as can be found here:

Will be more than happy to assist in any way needed during the discussion about this topic.

Thanks in advance for your review,
Eyal Itkin

Roland McGrath

unread,
Sep 25, 2025, 10:38:45 PM (5 days ago) Sep 25
to gener...@googlegroups.com
I've only looked at your paper briefly, but I'm not sure this offers anything over `ld -r` + `objcopy --localize-hidden` as can already be used today (or `--globalize-symbol=...`, `--keep-global-sym=...`, etc.).  How does an ET_STAT file differ from an ET_REL file whose symbols have been rewritten to be STB_LOCAL when not "exported'?  New ELF format features are not always required to use ELF in new ways.  (But AFAICT this is a fairly well-established way, not a new one--just an arcane one.)

--
You received this message because you are subscribed to the Google Groups "Generic System V Application Binary Interface" group.
To unsubscribe from this group and stop receiving emails from it, send an email to generic-abi...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/generic-abi/5d1201ad-0d8d-47ec-8ab6-4316e4401fean%40googlegroups.com.

Eyal Itkin

unread,
Sep 26, 2025, 12:47:55 PM (4 days ago) Sep 26
to Generic System V Application Binary Interface
Thanks for the reply. Indeed in my paper I do present the option of using `ld -r`, the downsides for it and how I used it as a basis for my proposed format.

And more specifically:
1. There are helper projects (such as https://github.com/tux3/armerge) that aim to provide similar (if incomplete) support for adjusting static libraries, and indeed use a similar approach of `ld -r` and various objcopy commands as suggested.
2. The author of `armerge` is supporting my proposal and they describe it better than I can ever describe it, so I recommend reading their feedback as cited: source.
3. If my library attempts to statically link to another library, the handling is more complex (more than just "--localize-hidden"):
 a) One will need to also unpack the static library of the dependency - Unpacking has several issues due to possibly multiple occurrences of same name file (even in same archive)
 b) Using "--localize-symbol" per symbol of the statically compiled dependency is cumbersome - Projects don't usually have a list of the APIs of other projects
 c) Using "--keep-global-symbol" is quite messy given that shared libraries often use a version.map for it and now we force project to somehow juggle between these two lists of symbols
4. And finally, in both cases ("--localize-hidden" and manual hiding/keeping of symbols), we would still have a relocation tied to the internal (secret) functions, thus blocking strip from removing their symbols from the binary:
"
strip -Nsecret_function unified_lib.o
strip: not stripping symbol `secret_function' because it is named in a relocation
"

Given that objcopy does not support the option to resolve relocations related to updated symbols (local/global), the proper way to handle them (so to enable stripping the symbol) is to have ld support for the relocation resolution, which is indeed what I aim for in my proposal.

In the end, it might be possible to use the existing ET_REL e_type alongside more common/arcane ld flags and objcopy flags. However, as mentioned in my paper, I believe the correct approach is a new e_type:
1) Today ET_REL doesn't offer symbol visibility features when processed by ld - Changing that or changing the behavior of `ld -r` is a compatibility risk.
2) There are quite a few downsides for these flags (as shown above) aside from the process being far from elegant.

To summarize, my proposal aims to officially define the feature-set for a static library and have a dedicated e_type for it in the ELF format (coupled with official ld support), just as was done long ago for shared libraries (ET_DYN). 

Roland McGrath

unread,
Sep 26, 2025, 3:46:18 PM (4 days ago) Sep 26
to gener...@googlegroups.com
There is certainly a case to be made for having better integration in tools to produce the kinds of ELF files you want.  I don't think you've done anything to make a case for any new ELF format features to enable building tools with the semantics you'd like to have.

Eyal Itkin

unread,
Sep 26, 2025, 5:09:24 PM (4 days ago) Sep 26
to Generic System V Application Binary Interface
First, I'm happy we agree that there is a case to be made for better integration of tools for producing more optimal ELF files for static libraries.

As for the means of doing so, as I suggested in the paper and in this thread, the ELF file will need to either keep using the e_type of ET_REL, or use a new value (ET_STAT) that will be allocated for it. I admit I might not fully understand the cases in which an e_type value is allocated, yet I will point out there is a value of ET_DYN (shared libraries) and even a value for core dumps (which strictly speaking, are not executable files).

If the value of ET_REL will be kept, it will now serve 3 different roles, with completely different meanings and feature sets:
1) The plain compilation output - the compiler-produced object-code file
2) The plain amalgamation of multiple object-code files using the `ld-r` file - Which as discussed, involves almost no logic on behalf of the linker, which doesn't resolve relocations nor does it apply visibility semantics
3) A more complex amalgamation of multiple object-code files, that is done in the spirit of creating ET_DYN files, and that shares most of the logic with them, as shown in my proof-of-concept implementation on top of GNU's ld.

I agree this is feasible solution. However, from a compatibility standpoint changing the behavior of the existing `ld -r` flag is probably out of the question. And so, if a new linker flow is anyway being suggested in order to create a new binary ELF format, why shouldn't we assign a new e_type for it and make it official?

I do not know what are the official definitions for the exact scope of each existing e_type so to be able to decide if the new format falls within the existing scope or outside of it. If there are such, I believe it would be productive for this thread to discuss them and compare them to the requested format. In addition, I also do not know the rules by which new values are allocated, and would appreciate it if those could be shared as well given the nature of this thread.

What I do know is that there is plenty of room in the existing enum, and there is no risk of bloating the use of the e_type field with many new values, as the ask here is to align the static libraries with the attention that the dynamic libraries have already received. Given there are are only 2 types of such libraries, one of which is already covered by the standard, I do not anticipate a flood of new such e_type values if the "gates will be opened" for this specific request.

Obviously, the esteemed forum here has the final say, and any decision that you make will be appreciated and respected. When deciding about the proposal I made, I hope you will take into account the time and effort that went into preparing the paper and submitting this proposal, as well as the feedback the initial proposal received when it was circled about roughly 2 months ago in the community. I would not have taken the effort to work on it if I wouldn't have believed there are real gaps in the current tooling that require improvement, and I wouldn't have submitted my proposal to you if I wouldn't believe that this is the correct approach to help address these industry-wide issues.

Thanks again for your time,
Eyal

connor horman

unread,
Sep 26, 2025, 9:41:03 PM (4 days ago) Sep 26
to gener...@googlegroups.com
Yeah, I'm going to strongly agree with the things above - we have plenty of e_type space, and static libraries as either `ld -r` ET_REL objects or as .a files are second class in ELF compared for first-class ET_DYN objects. I also think that we do need the support that ET_DYN gets for static libraries, looking at projects like Rust, which have a difficult time keeping internal symbols from colliding in diagnosable (or non-diagnosable) ways when you think a static system library written in Rust to another, or to a program that uses Rust.

--
You received this message because you are subscribed to the Google Groups "Generic System V Application Binary Interface" group.
To unsubscribe from this group and stop receiving emails from it, send an email to generic-abi...@googlegroups.com.

Fangrui Song

unread,
Sep 27, 2025, 1:17:09 PM (3 days ago) Sep 27
to Generic System V Application Binary Interface
There is some misinformation.

>  If different visibility attributes are specified for distinct references to or definitions of a symbol, the most constraining visibility attribute must be propagated to the resolving symbol in the linked object. The attributes, ordered from least to most constraining, are: STV_PROTECTED, STV_HIDDEN, STV_INTERNAL, and STV_EXPORTED.

In GNU ld-compatible linkers, output constrains visibility regardless of -r.
It is incorrect to state that "ET_REL doesn't offer symbol visibility features when processed by ld".
Non-relocatable outputs (ET_EXEC, ET_DYN) additionally convert symbols of hidden visibility to STB_LOCAL binding.

> Similarly to shared objects, static bundle objects will resolve relocations for local symbols, instead of keeping them as possible hook points in the finalized binary

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

---

ET_REL object file already serve different roles.

- Compiler output (e.g. cc -c)
- Relocatable linking output - These files can be:
  * Used directly as input for executable linking (ld -r a.o b.o -o ab.o; ld ab.o)
  * Loaded by custom loaders (e.g., kernel modules in Linux)
  * Merged further with other relocatable files (ld -r a.o b.o -o ab.o; ld -r ab.o c.o -o abc.o)

The proposed static bundle object appears to cover a subset of existing ET_REL use cases while adding a new e_type code. I don't see this as a necessary addition.

---

In the current relocatable linking based approach, we should also consider COMDAT section groups when using C++, which enable name-based deduplication (binding is ignored).

- Compile with hidden symbols by default. Mark necessary symbols as exported
- Run ld -r --force-group-allocation
- Process the output with objcopy --localize-hidden with possibly other options.

objcopy --keep-global-symbols=filename can be utilized as well, similar to how we use a version scriot to create a shared object.

I agree that we might need better integration in tools (including the build system) to produce the kinds of ELF files you want.

Rafael Ávila de Espíndola

unread,
Sep 27, 2025, 2:05:36 PM (3 days ago) Sep 27
to gener...@googlegroups.com
Hi,

First of all, thanks. The use of .a files with their different semantics always felt a bit odd.

Having said that,  I think you make a good case for a new linker command line (--static-lib?), not a new elf file type.

The options should not combine sections or remove relocations so that gc sections, icf, and section placement still work to the best of their performance.

The option should localise symbols that would be hidden if this was producing a shared library.

Basically,  a .c file with a public function that calls a static one, when compiled with -ffunction-sections, should produce the same result as one of the functions being moved to another file, made hidden, and the two object files linked with the new option.

Thanks,
Rafael

Eyal Itkin

unread,
Sep 27, 2025, 3:29:58 PM (3 days ago) Sep 27
to gener...@googlegroups.com
Hi,

The suggestion to add a new ld flag (--static-lib) and use it to localize symbols as is done in --shared, still leaves two important points unaddressed:
1. If internal function symbols (turned local) will keep their relocations, said symbols will fail to be stripped, and the binary will "leak" all function names. I am aware this also happens when -ffunction-sections is used (which is a different topic) yet developers can choose not to use this flag. Shouldn't there also be an option for closed-source projects to maximize the stripping of their binaries?
2. If no new e_type value will be added to the standard, what will be the basis of convincing the maintainers of ld to extend the linker to support a new format/behavior? I fail to understand what is the industry method of declaring this new format for static libraries which will then be followed by implementation by all toolchains.

I will also add that having a different e_type than ET_REL also means that the linker will be able to differentiate between the two. For instance, this can allow for dedup of static libraries at command line if pkg-config causes the same static library to be passed more than once (as often happens, and is cited in my paper). This once again brings us to static libraries being first class citizens (like shared libraries) which allows them the same dedup/stripping features as exist for shared libraries.

Thanks again,
Eyal


--
You received this message because you are subscribed to the Google Groups "Generic System V Application Binary Interface" group.
To unsubscribe from this group and stop receiving emails from it, send an email to generic-abi...@googlegroups.com.

Ali Bahrami

unread,
Sep 27, 2025, 4:41:50 PM (3 days ago) Sep 27
to gener...@googlegroups.com
Adding a new object type to the generic ABI faces a high hurdle,
because it will impose costs on anyone maintaining an ELF toolchain,
as well adding complexity to a standard that benefits greatly from being
relatively simple.

It's telling that in 40+ year run, ELF has only needed 4 types, REL, DYN,
EXEC, and CORE. There's nothing new about static linking, so it seems
surprising that a new type to cater to it would be needed.

I delayed commenting until I had a chance to read the paper. Having
read it, I agree with the others that this really still sounds like something
an ET_REL can handle, and agree particularly with Rafael's comment:

On 9/27/25 12:05 PM, Rafael Ávila de Espíndola wrote:
> Having said that, I think you make a good case for a new linker command
> line (--static-lib?), not a new elf file type.

If I understand this project correctly, your goal is to produce a
relocatable-like object that is self contained, like a shared object
would be, and which only exports the global symbols that make
up an interface. The idea is that you could link to this, much as
one does to a shared library, except that the bits will be copied
into the final object.

One big thing that distinguishes an executable or shared
object from a relocatable object, is that EXEC/DYN go through
a process of finalization, where things like symbol resolution
are done to turn them into complete objects. I believe that your
paper is describing the process of finalizing an ET_REL.

You can definitely do that. Solaris kernel modules are an example.
Our kmods are ET_REL, but are distinguished from regular ET_REL
by going through finalization. I can imagine optionally doing this for
"regular" relocatable objects. In reading your paper, I have the impression
that this is what you've already done, and I wonder what added benefit
comes from giving them this different type. Is there a reason that the
result needs to be identified specially as a static library, rather than as
just another relocatable object? Being able to make them ET_REL
would lower the number of changes needed greatly, for yourselves
as well as the rest of us.

- Ali

Ali Bahrami

unread,
Sep 27, 2025, 5:29:14 PM (3 days ago) Sep 27
to gener...@googlegroups.com
On 9/27/25 1:29 PM, Eyal Itkin wrote:
> The suggestion to add a new ld flag (--static-lib) and use it to
> localize symbols as is done in --shared, still leaves two important
> points unaddressed:
> 1. If internal function symbols (turned local) will keep their
> relocations, said symbols will fail to be stripped, and the binary will
> "leak" all function names. I am aware this also happens when -ffunction-
> sections is used (which is a different topic) yet developers can choose
> not to use this flag. Shouldn't there also be an option for closed-
> source projects to maximize the stripping of their binaries?

Not as a primary motivation, no. Not because I care about hiding IP
one way or the other, but because I don't think that sort of obfuscation
is a very effective barrier to a determined disassembler.

That's not to say that you're stuck keeping those symbols
(as local) though. It is also possible to rewrite such
relocations to be section relative (use a section symbol), rather
than the original symbol. That achieves some obfuscation,
which might make someone trying to hide IP happy, but which
will probably making someone using a symbolic debugger to fix
it unhappy. That sort of rewriting is done when local symbols
are dropped, usually as the result of a special option that
causes it, or the use of a mapfile/linker-script.

I'm not clear on what special problem is caused by groups
(-ffunction-sections). I'd expect group processing to be one
of the things done by the finalization step mentioned previously.


> 2. If no new e_type value will be added to the standard, what will be
> the basis of convincing the maintainers of ld to extend the linker to
> support a new format/behavior? I fail to understand what is the industry
> method of declaring this new format for static libraries which will then
> be followed by implementation by all toolchains.

What added support is needed?

Clearly you need to know it when you create the thing,
so a creation time option is needed.

Afterwards though, it's just another .o, albeit one
that was built unusually. Most of what's been said here
is based on the assumption that there is nothing special
for the link-editor to do at that point. Not true?

>
> I will also add that having a different e_type than ET_REL also means
> that the linker will be able to differentiate between the two. For
> instance, this can allow for dedup of static libraries at command line
> if pkg-config causes the same static library to be passed more than once
> (as often happens, and is cited in my paper). This once again brings us
> to static libraries being first class citizens (like shared libraries)
> which allows them the same dedup/stripping features as exist for shared
> libraries.
By itself, that's not a strong reason to invent an entirely
new object type, which all ELF toolchains will be forced to
understand. If it really was seen to be a problem in practice,
there are probably smaller solutions.

- Ali

connor horman

unread,
Sep 27, 2025, 6:15:57 PM (3 days ago) Sep 27
to gener...@googlegroups.com
One thing that a separate type can have that just ET_REL can't have (which generalizes the deduplication issue) is that linkers aren't going to treat two ET_REL files on the command line differently. However, static libraries ought to be treated more like .a files and ET_DYN objects. Notably, I'd expect any elf-based static library to be affected by `--as-needed` options like shared objects are. Similarly, I would not expect linkers to apply --as-needed to normal object files. Deduplication is indeed another issue. Many tools will happily add a static library to a command line because it is benign to do so if multiple copies end up (as long as you don't set --whole-archive). If static libraries are converted to an ELF-based solution, I would 100% expect them to be suitable for deduplication so that they retain this property. Frankly, I don't think ET_REL would be suitable as a library format for that reason - adding it to the link line is not idempotent.

--
You received this message because you are subscribed to the Google Groups "Generic System V Application Binary Interface" group.
To unsubscribe from this group and stop receiving emails from it, send an email to generic-abi...@googlegroups.com.

Rafael Ávila de Espíndola

unread,
Sep 28, 2025, 3:38:46 AM (2 days ago) Sep 28
to gener...@googlegroups.com
Hi,

A nice thing about elf is that a producer can decide how granular sections are. If you are ok with degrading the final result a bit, you could have --static-lib --combine-secs. It would instruct the linker to combine sections and remove relocations when possible.


The second point is better, as handling duplicates is something different about static libraries.

The question is if it is worth it. If you add the above options to any linker, you can stop shipping .a files tomorrow. With a new file type, you will need to wait for all customers to upgrade their linkers.

Thanks,
Rafael

Rafael Ávila de Espíndola

unread,
Sep 28, 2025, 7:43:16 AM (2 days ago) Sep 28
to Ali Bahrami, gener...@googlegroups.com
Ali Bahrami <ali_e...@emvision.com> writes:

>> I will also add that having a different e_type than ET_REL also means
>> that the linker will be able to differentiate between the two. For
>> instance, this can allow for dedup of static libraries at command line
>> if pkg-config causes the same static library to be passed more than once
>> (as often happens, and is cited in my paper). This once again brings us
>> to static libraries being first class citizens (like shared libraries)
>> which allows them the same dedup/stripping features as exist for shared
>> libraries.
> By itself, that's not a strong reason to invent an entirely
> new object type, which all ELF toolchains will be forced to
> understand. If it really was seen to be a problem in practice,
> there are probably smaller solutions.

I just realized that probably the simplest solution is to have the new
--static-lib option produce a .a file with a single .o file in it.

Cheers,
Rafael

Eyal Itkin

unread,
Sep 28, 2025, 12:03:43 PM (2 days ago) Sep 28
to gener...@googlegroups.com, Ali Bahrami
The notion of a phased deployment by shipping both a .a that includes a single ET_REL .o file and an .sbo file, later to deprecate the former, is indeed mentioned in my proposal.

One point that I'm still unsure about is the effort/timeline notion that was suggested in the thread. No change will be immediate - Any change that hopes to get wide adoption by users will need to wait for support that will be added to ld (if required) and that will gradually propagate to a release in an LTS distro of one OS or another, to be picked up by projects. Projects nowadays often don't use a Makefile, but some other technology on top of it, such as Bazel, CMake or Meson. These technologies will need to support whatever proposal will be decided (objcopy commands, ld linker commands, etc.) and offer it to users through their API. For compatibility reasons, every solution aside from a .a archive that wraps something, will also impact packaging, pkg-config definitions, and build API if a phased approach is being used or a project wishes to switch to the new offering.

These steps will be needed for any replacement of the current static .a archives, so none of them will be immediate for the average user. And while arcane ld flags or objcopy flags might be available today, the average user that uses Bazel/CMake/Meson will never have access to these tools out of the box, meaning that most projects will either never use them, or will have to integrate scripts for these tools on their own in their build environment, multiplied by all projects out there.

I do understand that adding an enum value will cause work for all toolchains. The addition of the enum option itself for binutils was implemented by me as part of the POC, and it is a very minor commit if one wishes to only be aware of the format without yet supporting it.

However, doesn't any decision of this forum (put aside adding new e_machine values) is a decision that impacts all toolchains? And that by definition adds/extends something that wasn't defined (or at least fully defined) in the 40+ years of this standard? Do we really want to fix only some of the issues projects complain about when using static archives (such as the 3 years  old rust bug for the standard library), and leave some of them open, including keeping the hack of using a .a archive to wrap whatever we replaced under the hood?

I never anticipated that a mainstream project would be able to use the new proposed format before Ubuntu 28.04. And I have the time and commitment to help relevant projects to prepare and integrate the required updates. But this will only be relevant if we start at some point. If, instead, we keep the notion that the last 40+ years were good enough, then the next 40+ years will look exactly the same and no progress will ever be made.

--
You received this message because you are subscribed to the Google Groups "Generic System V Application Binary Interface" group.
To unsubscribe from this group and stop receiving emails from it, send an email to generic-abi...@googlegroups.com.

Eyal Itkin

unread,
Sep 28, 2025, 2:52:16 PM (2 days ago) Sep 28
to Generic System V Application Binary Interface
Going over the thread and trying to summarize the points that were raised, it seems that there are roughly the following four main options.

Option #1 - Do nothing. No substantial claim was made to showcase the existence of a gap that requires addressing, or that is worth being addressed.

Option #2 - This is a tooling issue. objcopy and ld might need to offer improved features so to handle symbol scoping issues (scoping, not stripping). Please note that objcopy might localize symbols yet won't finalize the ET_REL, hence relocation will be kept, internal symbols will be kept, and no stripping will be available. I doubt that use of objcopy flags will be widely adopted by the average project, making this more of a niche solution. If a change to ld will be introduced, it would be in the form of finalizing relocations, which pretty much brings us to option #3.

Option #3 - The linker should support --static-library flag. There is indeed a strong case for a new static library format, replacing the existing .a archive. The new linker flag will create an ET_REL object as this falls within the scope of the existing e_type, and the process will support some sort of finalization to relocations, even if probably lesser than offered for the ET_DYN case. Still, there is no strong case for the linker to treat the static libraries differently than plain object-code files, unlike the way shared libraries are handled. This will prevent the ability to dedup static libraries from the command line, or the ability to have an "--as-needed" equivalent. I will also point out that "--ffunction-sections" alongside "--gc-sections" is out of the question for closed-source projects, as by definition the sections names are the function names, which cancels some of the benefits we wanted to achieve in the finalization step. The leading case is to keep on bundling this ET_REL file within a .a archive, so to maintain compatibility. It is unclear what are the guidelines by which ld will implement said support, as it would still require some formal recognition and standardization.

Option #4 - Add a new e_type (ET_STAT) and treat static libraries as first-class citizens. There is a strong case to allow the linker (and other tools) to differentiate between plain ET_REL files and static libraries, hence a new e_type is needed. In addition, option #3 already requires ld to do all the heavy lifting, hence the only delta is the added support for dedup on command line and "--as-needed" equivalents (which is pretty minor). There will most probably be additional cases in the future (or that we haven't articulated yet) that require distinction between libraries and plain object-code files, and this provides the infrastructure for doing so. Having a new e_type will help communicate that both Shared Libraries and Static Libraries are well defined formats which are defined and supported by the ELF standard. This will promote the adoption of the new format throughout toolchain and compilation wrappers (Bazel/CMake/Meson) helping to deprecate the existing static archives. Format will be shipped on it's own (.sbo file, without .a file) and could use a phased approach as suggested in the paper.

Regards,
Eyal
Reply all
Reply to author
Forward
0 new messages