It has been said in this thread before, but I fail to see how the atom
model is an actual improvement over the fine grained section model. It
seems to be artifically restricted for no good reasons.
Sections come with a huge amount of bloat and overhead that atoms do not.
Lets stop thinking about lld as one linker, and instead think of it is
two different ones. We’ll build a Camp B linker which is the best of
breed section based linker. It will support linker scripts and do
everything better than any existing section based linker. The first
step of this is to do what Rui proposes and rip atoms out of the model.
This is another item that has been irritating me. While it is a very
laudable goal to not depend on linker scripts for the common case, not
having the functionality of fine grained output control is certainly a
problem. They are crucial for embedded developers and also at least
significant for anything near a system kernel.
I’m not saying that the linker should eschew fine grained control, I’m saying it should dump linker scripts (and replace them with something better). Are you going to argue that linker scripts are great, or that they are what we would end up with if we weren’t driven by backwards compatibility goals?
-Chris
It has been said in this thread before, but I fail to see how the atom
model is an actual improvement over the fine grained section model. It
seems to be artifically restricted for no good reasons.
Sections come with a huge amount of bloat and overhead that atoms do not.
Caveat: My response isn’t in favor of one way over the other, but providing some explanations or trying to frame the trade-offs in a more explicit form.
Sections come with some size overhead that an atom doesn’t because an atom is contained within a section, however, atoms come with a link time cost that sections don’t. Trade off. 
The atom model is effective for minimizing the size of on disk representation or working around limited object container formats. Being able to just append sections is a trade off for speed of linking versus size of inputs at the moment (which is a tricky trade-off as the speed of linking starts to approach the size of the objects being linked). That said, I don’t think any of the current linkers are currently I/O bound here either.
Lets stop thinking about lld as one linker, and instead think of it is
two different ones. We’ll build a Camp B linker which is the best of
breed section based linker. It will support linker scripts and do
everything better than any existing section based linker. The first
step of this is to do what Rui proposes and rip atoms out of the model.
This is another item that has been irritating me. While it is a very
laudable goal to not depend on linker scripts for the common case, not
having the functionality of fine grained output control is certainly a
problem. They are crucial for embedded developers and also at least
significant for anything near a system kernel.
I’m not saying that the linker should eschew fine grained control, I’m saying it should dump linker scripts (and replace them with something better). Are you going to argue that linker scripts are great, or that they are what we would end up with if we weren’t driven by backwards compatibility goals?
Linker scripts are worse than everything - except for the alternatives that we know about. Any particular suggestions here?
-eric
> It has been said in this thread before, but I fail to see how the atom
> model is an actual improvement over the fine grained section model. It
> seems to be artifically restricted for no good reasons.
Sections come with a huge amount of bloat and overhead that atoms do not.
I don't buy that as far as the internal representation is concerned.
On-disk format as Eric said is a somewhat different question.
>> Lets stop thinking about lld as one linker, and instead think of it is
>> two different ones. We’ll build a Camp B linker which is the best of
>> breed section based linker. It will support linker scripts and do
>> everything better than any existing section based linker. The first
>> step of this is to do what Rui proposes and rip atoms out of the model.
>
> This is another item that has been irritating me. While it is a very
> laudable goal to not depend on linker scripts for the common case, not
> having the functionality of fine grained output control is certainly a
> problem. They are crucial for embedded developers and also at least
> significant for anything near a system kernel.
I’m not saying that the linker should eschew fine grained control, I’m
saying it should dump linker scripts (and replace them with something
better). Are you going to argue that linker scripts are great, or that
they are what we would end up with if we weren’t driven by backwards
compatibility goals?
I haven't seen the better alternative yet. It is hard to reason about
vaporware. I'm not particulary attached to linker scripts, they are
certainly a horrible language. But the lack of support is certainly a
show stopper for those areas where the functionality is needed.
How is a linker supporting at least a major part of that functionality
going to be different from a linker that accepts linker scripts as
input?
Joerg
I very much care about the functionality provided by linker scripts (for
embedded systems and kernel work), but I do agree that most current
script formats are hard to use, debug, reason about, etc... I have
often wondered whether embedding Python might be a better choice.
Take a look at how debuggers have migrated through the years. They too
used to have their own script format. Now most (all?) popular debuggers
do scripting through embedding an actual programming language. This
could be a better way forward for linkers as well -- embed Python in the
linker, define a Python API for linkable item placement, entry point,
symbol operations, etc..., and then you also have the rest of Python at
your fingertips.
-- Meador
Linker scripts are worse than everything - except for the alternatives that
we know about. Any particular suggestions here?
I very much care about the functionality provided by linker scripts (for
embedded systems and kernel work), but I do agree that most current
script formats are hard to use, debug, reason about, etc… I have
often wondered whether embedding Python might be a better choice.
Take a look at how debuggers have migrated through the years. They too
used to have their own script format. Now most (all?) popular debuggers
do scripting through embedding an actual programming language. This
could be a better way forward for linkers as well – embed Python in the
linker, define a Python API for linkable item placement, entry point,
symbol operations, etc…, and then you also have the rest of Python at
your fingertips.
I mostly care about specifying address where specific symbols will be placed and specifying the memory layout of the platform. I normally use attribute((section(“”))) to place the symbols in their own sections and then use the linker script to place the sections at the required addresses. How would this be accomplished without linker scripts?
I’d prefer to use an "attribute((address(0x1234)))” myself. That way you can control platform specifics with #ifdefs.
-Chris
But that way you have to do layout by hand in C. Generally you won't
know the size of the preceding code or data so you won't know what
address to put things at at the granularity of a single C level
object/function. Better to say "put this in the ROM section" and set
the address of the ROM section once in a linker script and let the
linker do the layout.
The real use case is on platforms, like ARM, where control registers are
mapped to a specific address range. Then it is useful to put an object
that deals with the control registers at a specific address.
__attribute__((address(0x1234))) can be replaced with a platform
specific linker script. Which is better? I don't know, I haven't spent
any time comparing them.
Why would you want to put an object at the address of some registers?
You would just want a cast would you not?
e.g. regs = (struct MyRegBlock *)0x1234
>
> Take a look at how debuggers have migrated through the years. They too
>>
>> used to have their own script format. Now most (all?) popular
debuggers
>> do scripting through embedding an actual programming language. This
>> could be a better way forward for linkers as well -- embed Python in
the
>> linker, define a Python API for linkable item placement, entry point,
>> symbol operations, etc..., and then you also have the rest of Python at
>> your fingertips.
>
>
> I mostly care about specifying address where specific symbols will be
placed
> and specifying the memory layout of the platform. I normally use
> __attribute__((section(""))) to place the symbols in their own sections
and
> then use the linker script to place the sections at the required
addresses.
> How would this be accomplished without linker scripts?
>
>
> I’d prefer to use an "__attribute__((address(0x1234)))” myself. That
way
> you can control platform specifics with #ifdefs.
But that way you have to do layout by hand in C. Generally you won't
know the size of the preceding code or data so you won't know what
address to put things at at the granularity of a single C level
object/function. Better to say "put this in the ROM section" and set
the address of the ROM section once in a linker script and let the
linker do the layout.
The real use case is on platforms, like ARM, where control registers are
mapped to a specific address range. Then it is useful to put an object
that deals with the control registers at a specific address.
__attribute__((address(0x1234))) can be replaced with a platform
specific linker script. Which is better? I don't know, I haven't spent
any time comparing them.
There is another important use of linker scripts, namely having a notion of
separate load and virtual addresses. This is important for e.g. an
initialized .data section which is stored in ROM, but needs to be copied to
writable memory.
For more information on linker scripts, see my post "linker script
findings": '[LLVMdev] [lld] Linker script findings.' - MARC
-- Sean Silva
>
> Take a look at how debuggers have migrated through the years. They too
>>
>> used to have their own script format. Now most (all?) popular debuggers
>> do scripting through embedding an actual programming language. This
>> could be a better way forward for linkers as well -- embed Python in the
>> linker, define a Python API for linkable item placement, entry point,
>> symbol operations, etc..., and then you also have the rest of Python at
>> your fingertips.
>
>
> I mostly care about specifying address where specific symbols will be
placed
> and specifying the memory layout of the platform. I normally use
> __attribute__((section(""))) to place the symbols in their own sections
and
> then use the linker script to place the sections at the required
addresses.
> How would this be accomplished without linker scripts?
>
>
> I’d prefer to use an "__attribute__((address(0x1234)))” myself. That way
> you can control platform specifics with #ifdefs.
But that way you have to do layout by hand in C. Generally you won't
know the size of the preceding code or data so you won't know what
address to put things at at the granularity of a single C level
object/function. Better to say "put this in the ROM section" and set
the address of the ROM section once in a linker script and let the
linker do the layout.
Chris is referring to memory-mapped registers that are literally at a fixed
address in the hardware. These sorts of attributes already exist, e.g.
>
>
>>
>> >
>> > Take a look at how debuggers have migrated through the years. They
too
>> >>
>> >> used to have their own script format. Now most (all?) popular
>> >> debuggers
>> >> do scripting through embedding an actual programming language. This
>> >> could be a better way forward for linkers as well -- embed Python in
>> >> the
>> >> linker, define a Python API for linkable item placement, entry point,
>> >> symbol operations, etc..., and then you also have the rest of Python
at
>> >> your fingertips.
>> >
>> >
>> > I mostly care about specifying address where specific symbols will be
>> > placed
>> > and specifying the memory layout of the platform. I normally use
>> > __attribute__((section(""))) to place the symbols in their own
sections
>> > and
>> > then use the linker script to place the sections at the required
>> > addresses.
>> > How would this be accomplished without linker scripts?
>> >
>> >
>> > I’d prefer to use an "__attribute__((address(0x1234)))” myself. That
>> > way
>> > you can control platform specifics with #ifdefs.
>>
>> But that way you have to do layout by hand in C. Generally you won't
>> know the size of the preceding code or data so you won't know what
>> address to put things at at the granularity of a single C level
>> object/function. Better to say "put this in the ROM section" and set
>> the address of the ROM section once in a linker script and let the
>> linker do the layout.
>
>
> The real use case is on platforms, like ARM, where control registers are
> mapped to a specific address range. Then it is useful to put an object
that
> deals with the control registers at a specific address.
> __attribute__((address(0x1234))) can be replaced with a platform specific
> linker script. Which is better? I don't know, I haven't spent any time
> comparing them.
Why would you want to put an object at the address of some registers?
You would just want a cast would you not?
e.g. regs = (struct MyRegBlock *)0x1234
This causes you to have to be constantly dereferencing, which can result in
a huge amount of syntactic overhead. CMSIS does this really consistently
and do a good job at it:
http://www.keil.com/pack/doc/CMSIS/Core/html/group__peripheral__gr.html
But it's sort of an all-or-nothing thing to organize the peripheral headers
like that, and many platforms don't (MSP430, AVR, smaller PIC's), instead
preferring to have e.g. `volatile uint8_t Foo;` for each hardware register
instead of putting things in structs.
-- Sean Silva
Having worked with both forms (struct vs. individual symbols), I really prefer the struct mechanism. Especially in more recent processors, the hardware register layout is very consistent from one peripheral to the next, and when using the struct, it can dramatically reduce the number of symbols one has to deal with.
So, my $0.02 (having only a cursory understanding of this thread) is to hopefully allow the struct mechanism.
While slightly off topic of LLD improvement,
volatile uint8_t attribute((address(0x1234))) foo;
is slightly nicer than
(*(volatile uint8_t *)0x1234)
because the latter ends up often being done in a header file as a macro, usually as something like:
#define foo (*(volatile uint8_t *)0x1234)
The former behaves with all the language scoping rules, so a foo within a function or as a parameter has the expected
behavior. The latter has all the downsides that macro usage can come with.
On topic – Sean – I think that is a great document on linker scripts and their usage and meaning.
Kevin Smith
I'm sorry if my suggestion gave an impression that I disregard the Mach-O
port of the LLD linker. I do care about Mach-O. I do not plan to break or
remove any functionality from the current Mach-O port of the LLD. I don't
propose to remove the atom model from the linker as long as it seems to be
a good fit for the port (and looks like it is).
As to the proposal to have two different linkers, I'd think that that's not
really a counter-proposal, as it's similar to what I'm proposing.
Maybe the view of "future file formats vs the existing formats" (or
"experimental platform vs. practical tool") is not right to get the
difference between the atom model and the section model, since the Mach-O
file an existing file format which we'd want to keep to be on the atom
model. I think we want both even for the existing formats.
My proposal can be read as suggesting we split the LLD linker into two
major parts, the atom model-based and the section model-based, while
keeping the two under the same project and repository. I still think that
we can share code between the two, especially for the LTO, which is I
prefer to have the two under the same repository.
That approach makes sense to me personally.
-Chris
[snip] Nice write up Sean. I’d like to second the notion that linker scripts are important, especially in the embedded/kernel world. I use linker scripts to give addresses to register blocks and to put R/W initialized data in flash that can be copied to RAM on start up. One cool thing about putting register addresses in linker scripts is that you can change the placement of registers without having to rebuild the source. For example, I have a small embedded kernel that can run in both MMU and non-MMU mode. In the former case the peripheral registers are mapped into the kernel’s virtual address space, in the latter case they are placed at their actual address. It is nice to be able to do that without having to recompile drivers. Having said that, I would be all for a new linker script format. I find the GNU linker’s scripts counter intuitive and hard to read. The lack of linker scripts is the main thing that keeps me from being able to use lld right now. -Rich
Hi,
There are a lot of advantages to keep on improving the atom model and working on that model.
The atom model allowed lld to have a single intermediate representation for all the formats ELF/COFF/Mach-O. The native model allowed the intermediate representation to be serialized to disk too. If the intermediate representations data structures are made available to scripting languages most of all linker script script layout can be implemented by the end user. A new language also can be developed as most of the users need it and it can work on this intermediate representation.
The atom model also simplified a lot of usecases like garbage collection and having the resolve to deal just with atoms. The section model would sound simple from the outside but it it has its own challenges like separating the symbol information from section information.
The atom model also simplifies testing as there is one unique/nice way to test the core linker independent of the format.
In addition to testing, there are tools that are designed to convert ELF to COFF or viceversa, which makes lld to support these usecases by design.
Most of all embedded users want to reduce the final image size by compiling code using -ffunction-sections and -fdata-sections, which makes the atom model directly model it. Thanks to Espindola for adding support for -fno-unique-section-names which makes lld and the atom model more useful.
lld has already proven that it can link most of our llvm tools and self host with reasonable performance, I dont see why we dont want to continue with the Atom model.
Atom model also eases up dealing with LTO in general.
In summary, I would like to continue the ELF ports using the Atom model.
_If a section model is being chosen to model flavors lets not mixing it up with Atom model as I can see there would be very less code sharing._
Shankar Easwaran
I'm sorry, but I don't get why any of this requires an atom based
representation. Saying that a single intermediate representation for
ELF/COFF on one hand and Mach-O on the other is ironic given the already
mentioned hacks on various layers. Garbage collection doesn't become
more expensive when attaching more than one symbol to each code/data
fragment. Symbol resolution doesn't change when attaching more than one
symbol to each code/data fragment. The list goes on. The single natural
advantage is that you can use a single pointer to the canonical symbol
from a code/data fragment and don't have to use a list/array. Given the
necessary and expensive hacks for splitting sections into (pseudo)
atoms, that doesn't feel like a win. So once again, what actual
advantages for ELF or COFF have been created by the atom model? Mach-O
hardly counts as it doesn't allow the flexibility of the section model
as has been discussed before.
Joerg
The atom model is optimized when you compile the code with -ffunction-sections and -fdata-sections.
Once targets start having -fno-unique-section-names as the default the atom model looks more promising.
Everyone likes to have the image size small, and making -ffunction-sections/-fdata-sections (or) -fno-unique-section-names the default make sense and the atom model design directly has a relation to it. In fact it simplifies the linker to not have extra data structures IMO.
Shankar Easwaran