What does the ALIGN keyword do in linker scripts? I read many tutorials about linker scripts but I cant understand what really ALIGN do. Can any one explain it simply. Thanks!
A typical usage is
. = ALIGN(8);
This means: insert padding bytes until current location becomes aligned on 8-byte boundary. That is:
while ((current_location & 7) != 0)
*current_location++ = padding_value;
The ALIGN() instructions tell the linker that section(bss, text) should be this much aligned.
For a typical idea, you can take a look here (4.6.3 "Output Section Description")
e.g.
//.data is aligned by word size on the 32-bit architecture and direct it to the data section
For a 32-bit machine, it typically needs to be word aligned
.data : ALIGN(4)
{
*(.data*)
} > data_sdram
After some nasty behavior & unexpected results, here are my conclusions:
ALING(exp) works as expected only if exp is 2^ (power of 2) !!!
Some documentations shows this poorly, but some not at all!
https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_14.html
ALIGN will be eqivalent of
(. + exp - 1) & ~(exp - 1)
As you can see, there is a & (AND) with a mask (exp-1) which will work only if exp is 2^ !!!
Let's take this example:
.fini_array : {
. = ALIGN(4);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(1024);
} >FLASH : FLASH_PHDR =0xDD
Here, the last ALIGN(1024) will make sure that (.) cursor (or next address that will be used) is aligned to 1024 bytes. To illustrate this, I used 0xDD to fill padding areas that linker will introduce in order to fulfill 1024 divisible topic.
Here are the results:
As you can see, linker just added 316 bytes (0xDD) after useful data as padding, in order that (.) next cursor to be aligned to 1024.
Next cursor (address) is 31744 which is divisible by 1024.
Let's take a wrong example (unexpected results):
.fini_array : {
. = ALIGN(4);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(13);
} >FLASH : FLASH_PHDR =0xDD
The next (.) cursor will NOT be aligned to 13 bytes as one my expect !!!
The next (.) address is 31439 which is obviously wrong (unexpected) because masking in equivalent formula above with something that is not a full mask.
Hope this clarifies things a little bit!
. = ALIGN(8)
Corresponds to the following (working link script example using operators):
data = .;
. = ((data + 0x8 - 1) & ~(0x8 - 1)) - data;
There are two typical uses for ALIGN.
To align the start of a section to a required boundary
To pad a section to a required size.
/* . = ALIGN(BEGIN) ; equivalent to below, if VMA==LMA */ .section : ALIGN(BEGIN) { /* . = ALIGN(BEGIN) ; !!Not equivalent to above!! */ ... . = ALIGN(END); }
The first ALIGN ensure the starting value is a multiple of BEGIN as a power of 2. The 2nd ALIGN will ensure that the size of a multiple of END. Normally you will want them to be equal and powers of two which indicate how many address bits are needed and can help with caching.
For instance copy loops can be optimized with large transfer sizes if the size is prohibited by the linker script to have fixed size multiples.
The See below on reason why not to use this; it actually does nothing.ALIGN(BEGIN)
inside the '.section' would result in some junk at the beginning of the sections. See: FILL()
and =fill
for ways to control what is written.
Some example of structure that need to be aligned are,
- a vector table
- an mmu table
- time critical routines that need cache fills
.bss
and.initdata
for initialization efficiency
The Gnu ld syntax allows you the ability to use ALIGN
anywhere.
If you were to custom code structures with BYTE
, LONG
, you might need to align tables/structures in a section. This is fairly obtuse use of a linker scripts, but is possible and an exception to the opening two uses. However, for most beginning to understand ld
, that two uses are almost always the desired use.
Operation inside a section works as if all of the addresses are relative. So the start of the section is zero (and code commented not equivalent does not work due to this). As the last thing is . = ALIGN(...);
, this sets the size of the section because it is zero based. This will even work if the start address of the section is not aligned.
ALIGN
will dictate as to what is being aligned. VMA is the execution address. LMA is the load address or position in a binary; startup code will copy one to the other. For non-bare metal, a loader sets up everything and may process an ELF file to place sections at appropriate addresses. –
Sanitarium ALIGN()
directly. However, 90+% of all uses of ALIGN() are to set the current location. It can be used with expressions directly (good luck with that). –
Sanitarium © 2022 - 2024 — McMap. All rights reserved.