I have a linker file that I use as input for Gnu Arm Embedded Toolchain.
It contains, among other things, an output section like this:
.text :
{
. = ALIGN(4);
*(.text*)
*(.rodata*)
} > FLASH
, where FLASH is a MEMORY block.
My issue is that, when I compile a C++ file with LTO (link-time optimization), some of my code is put in non-".text" sections in the resulting object files. These sections seems to be consistently named:
.gnu.lto<SOMETHING>
As a result, they are not placed in my .text output section.
How can I map LTO input sections to my .text output section?
It turns out my issue was related to a misunderstanding in how the VMA and LMA statements work in GNU linker files. So, in essense the LTO section are mapped correctly. Thanks to anyone who spent time on this.
Related
I'm attempting to convert an assembly file to C++ for use as a small and easy to insert "trampoline" loader for another library. It is injected into another program at runtime, then loads a library, runs a function inside of it, and frees it. This is simply to avoid needing multiple lengthy calls to WriteProccessMemory, and to allow certain runtime checks if needed.
Originally, I wrote the code in assembly as it gave me a high degree of control over the structure of the file. I ended up with a ~128 byte file structured as followed:
<Relocation Header> // Table of function pointers filled in by the loading code
<Code>
<Static Data>
The size/structure of the header is known at compile-time, also allowing the entry point to be calculated, so there is very little code needed to load this.
The problem is that sharing the structure of the header between my assembler (NASM) and compiler (GCC) is... difficult, hence the rewrite.
I've come up with this series of commands to compile/link the C++ code:
g++ -c -O3 -fpic Loader.cpp
g++ -O3 -shared -nostdlib Loader.o
Running objcopy -O binary -j .text a.exe then gives a binary file only about 95 bytes in size (I manually inserted some padding in the assembly version to make it clear when debugging where "sections" are).
Only one problem (at least for this question), the variable offsets haven't been relocated (obviously). Viewing the binary, I can see lines like mov rcx, QWORD PTR [rip+0x4fc9]. Clearly, this will not be valid in a 95 byte file. Is there a way (preferably using GCC or a program in Binutils) that I can get a stripped binary with correct offsets? The solution doesn't have to be a post-process like objcopy, it can happen during any part of the build proccess.
I'd really like to avoid any unneeded information in the file, it wouldn't necessarily be detrimental, but this is meant to be super lightweight. The file does not need to be directly runnable (the entry-point does not have to be 0).
Also to be clear, I'm not asking for a simple addition/subtraction to all pointers, GCC's generated addresses are spread across memory, they should be up against the code.
Although incomplete and needing some changes, I think I've come up with a functioning solution for now.
I compile as before, but link with a slightly different command: g++ -T lnkscrpt.txt -O3 -nostdlib Loader.o (-shared just makes the linker complain about missing a DllMain).
lnkscrpt.txt is an ld linker script (https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_5.html#SEC5) as follows:
SECTIONS
{
. = 0x00;
.bss : { *(.bss) }
.text : { *(.text) }
.data : { *(.rdata) *(.data) }
/DISCARD/ : {*(*)}
}
This preserves the order I want and discards any other default sections.
Finally I run objcopy -O binary -j .* --set-section-flags .bss=alloc,load,contents a.exe
to copy over the remaining sections to a flat binary. The --set-section-flags option simply insures that the binary contains space allocated for the .bss section.
This results in a 128 byte binary, laid out in the exact same way as my custom assembly version, using correct offsets, and not containing any unneeded data.
With GNU Arm embedded toolchain, is it possible to change the default sections for symbols for a whole file?
I've previously worked with Rowley Crossworks, which has a parameter you can set for any source file or folder to change various default sections, for instance the default section for zeroed variables:
(from the Crossworks manual)
This is very useful to make sure a big application fit in flash on and RAM resource constrained microcontrollers. However, I'm unable to find any way to do this with the regular GNU Arm toolchain.
I'm aware that I can use __attribute__((section(".sectionname"))), but this requires code modifications, which is problematic when compiling the same code for different targets, some of which may not have more than one section.
The ideal solution would be a GCC command-line parameter to put for instance zeroed data in a custom section for a specific compilation unit. I could then apply this to specific files, folders or projects from CMake, without making any changes to the actual source code. Does something like this exist?
I was not able to find a command line parameter or similar for this functionality, but the comment from Lundin made me look into linker scripts in some more detail, and ended up with this:
.bss :
{
. = ALIGN(4);
__bss_start__ = .;
*main.cpp.obj*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} >RAM
.ethram (NOLOAD):
{
__ethram_start__ = .;
*(.ethram)
*(.bss*)
__ethram_end__ = .;
} >ETHRAM
In the above I explicitly state that in the output section .bss only main.cpp's .bss section should be included, and that it should be placed in regular RAM. By then having an unconstrained .bss in ETHRAM, the linker places other files' .bss sections there, and this was sufficient for my use.
It is also possible to explicitly exclude files from an output section, like this, but my application didn't need it:
.bss :
{
. = ALIGN(4);
__bss_start__ = .;
EXCLUDE_FILE(*main.cpp.obj*)*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} >RAM
It is possible with __attribute__, but to simply type out a section for the variable isn't sufficient. There must be such a section present in the linker script, which means you you have to manually modify that one (often called .ld/.lcf or some such, depending on target). Various dialects seem to exist depending on target, see the GCC linker manual for details.
Crossworks does that part for you - from what I recall they let you modify a more easy to use XML format so that you don't have to meddle with the the linker script directly. You can look at the output files from Crossworks and you'll find one with extension .ld or equivalent. And that's likely how your linker file for gcc for the given target platform should look like.
Could you change the compilation recipe to generate the .s file, apply awk / sed / etc... to adjust the sections to your liking, then assemble the result. It is kind of an old way of doing it, but is quite portable and reliable.
I want to add EWR(Execute/Write/Read) memory attribute to the .data section at compile time.
MSVC compiler can do this by simply adding the "/SECTION:.data,EWR" linker option.
But I don't know how to do this in GCC compiler (MinGW).
Please help!
The simplest way I could think of is adding a dummy file to the link with a .data.* section that has the desired flags. That dummy file is easy to produce using assembly:
.section .data.fake, "axw"
(assuming you are on an ELF platrofm, using gas).
Say, the file containing the above is called dummy.s, then you can either assemble it manually, and then add the result to the link
as dummy.s -o dummy.o
gcc <all your normal .o files> dummy.o # or `ld`
Or just pass the assebmly file to the driver:
gcc <all your normal files> dummy.s
Note that the assembler gives a warning:
Warning: setting incorrect section attributes for .data.fake
because of the unusual flags. It does set them as asked though.
Now, let me explain a little what is going on.
All the input .data* sections are merged into the output .data section. See the default linker script (ld --verbose):
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
The flags of the output section are the union of the flags of the input section (I'm pretty sure this behavior is documented in the linker manual). That is how the trick works. The flags for the segment holding the resulting .data are then also computed as the union of the flags of the sections it contains. See the output of readelf -lW to make sure you got the result you expect. I have
...
LOAD 0x002e28 0x0000000000003e28 0x0000000000003e28 0x000200 0x000208 *RWE* 0x1000
...
05 .init_array .fini_array .dynamic .got .got.plt *.data* .bss
I have a linker script in which I have defined a section for containing the checksum of a software image. Something like:
...
.my_checksum :
{
__checksum_is_here = .;
KEEP (*(.my_checksum))
. = ALIGN(4);
_sw_image_code_end = .;
} > IMAGE
...
The checksum is placed into that section by using objcopy --update-section.
I build an elf file by using the arm gcc compiler, and I can see this section and its value within it:
> arm-none-eabu-objdumph -h my_elf_file.elf
...
0 .text 0001496c 08010000 08010000 00010000 2**4
...
7 .my_checksum 00000004 080250c0 080250c0 000350c0 2**2
...
// Notice that 000350c0 is the file offset and 080250c0 is the LMA.
// The starting LMA is 08010000
And I can retrieve its value:
> xxd -s 0x000350c0 -l 4 my_elf_file.elf
000350c0: 015e 028e // I have checked this value and it is correct.
Now I generate a bin file by executing
> arm-none-eabi-objcopy -O binary --gap-fill 0xFF -S my_elf_file.elf my_elf_file.bin
Now, if I try to read the checksum value again, using the difference between the checksum LMA and the first section LMA (see above):
> xxd -s 0x150c0 -l 4 my_elf_file.bin
The result I obtain here is different from the one obtained in the elf file, that is, the checksum section has been removed by objcopy. (That's what I think at least).
Nevertheless, If I define this in my main.c file:
static volatile unsigned int __aux_checksum __attribute__((section(".my_checksum")));
...
int main() {
...
((void)__aux_checksum); // Avoid compiler/linker optimizations.
...
}
Now, if I replicate the same steps as above with the elf and bin files (using the proper offsets), I can retrieve the checksum from the bin file (elf and bin give the same result).
Questions
My first question is: I know that you can define a section using __attribute__((section)), but if you use a section already defined within the linker script, does this command changes its behaviour for placing the variable within the section, instead of creating a new one?
My second question is: Is this the only way for preventing objcopy of removing this particular section?
Lets answer your 2nd question first,
Is this the only way for preventing objcopy of removing this particular section?
You need a concept as documented in the gnu LD manual under SECTIONS.
4.6.8.1. Output Section Type
Each output section may have a type. The type is a keyword in parentheses. The following types are defined:
NOLOAD
The section should be marked as not loadable, so that it will not be loaded into memory when the program is run.
DSECT, COPY, INFO, OVERLAY
These type names are supported for backward compatibility, and are rarely used. They all have the same effect: the section should be marked as not allocatable, so that no memory is allocated for the section when the program is run.
The linker normally sets the attributes of an output section based on the input sections which map into it. You can override this by using the section type. For example, in the script sample below, the ROM section is addressed at memory location 0 and does not need to be loaded when the program is run. The contents of the ROM section will appear in the linker output file as usual.
SECTIONS {
ROM 0 (NOLOAD) : { … }
…
}
So what does that mean? Say you have debugging info in your objects. If you are burning a ROM image you probably don't want to place the debugging info in the object. As well, the BSS segment is all zero and there is no need to store it to ROM, but you need to clear our RAM (at the load address) to make way for it. The 'init value' for the .data section is initialized from ROM but resides in RAM. The concepts are 'loadable' and 'allocatable' and they have flags for them in an ELF file. By default your .my_checksum gets no flags. Ie, not allocated and not loadable like debug info.
I know that you can define a section using attribute((section)), but if you use a section already defined within the linker script, does this command changes its behaviour for placing the variable within the section, instead of creating a new one?
From the above,
The linker normally sets the attributes of an output section based on the input sections which map into it.
Your input sections flags get inherited by your output section. So you have put in at least allocatable as a flag.
I would suggest that you just put your checksum at the end of either .text or .data. For instance, input secttions .rodata (constant values) usually get put with the output .text. There is usually no need to invent another output sections unless you want some book keeping that wont get to the final image. Your __checksum_is_here label is sufficient to find it and you can look at this question on CRCs.
I would like to load .symtab into memory with gdb debugger.
At most two steps are required for a normal section (for some section, e.g. .text, .data, ... , step 1 can be skipped cause is automatically set by ld):
1 - Set the Alloc flag (in case of a special section) to the section in the ELF. This can be done in this way for a normal section.
arm-none-eabi-objcopy --set-section-flags .sectionName=alloc src.elf dst.elf
2 - Set the address to the section. This can be done in 2 ways for a normal section AFAIK
A - Specifying the section memory area in the LD script e.g. for text section:
.text :
{
*(.text)
*(.text*)
} > FLASH
B - Using again objcopy
arm-none-eabi-objcopy --change-section-address .sectioName=0x0ABCD src.elf dst.elf
since .symtab is generated automatically by the linker I cannot treat it as a normal section so none of the steps above works.
Does anyone have any idea on how to solve this?
I already successfully implemented a workaround that to generate a new elf stripping all unneeded sections, and this works but then you have to load two elfs and i'm looking for a cleaner solution.