GCC linker: move a symbol in a specified section - c

It is possible to move some of the functions in the code in a specific section
on the executable? If so, how?
For an application compiled with gcc, we have more source files, including
X.c. Each object is compiled from the associated source (X.o is obtained from X.c) and the linker produces a big executable.
I need two functions from X.c to be in a specific section in the
executable, say .magic_section. The reason I want this is
that the section will be loaded in another area of memory than the rest of the sections.
My problem is that I can not change the source X.c, otherwise I would have used
a specific flag, such as __attribute__ ((section ("magic_section"))) for
the functions.
I read something in the documentation for the linker and wrote a custom script for the linker, but I failed to specify in which section a particular symbol must be placed. I only managed to move a whole section.

On way you could do probably do it (not great, but should work in theory) is to use --function-sections and --data-sections, assuming your GCC version / architecture supports those options, and then manually call out all the functions & variables that need to go in a given file with a linker script.
This creates sections called like things .text.function_name or .data.variable_name. If you're familiar with assigning sections via gcc attributes, I'll assume you know what to do in the linker.
As an advantage, that would let you cherry-pick functions if you don't actually want the entire file to go in a magic section.

Unfortunately, without modifying your binary objects, dynamic linker or dynamic loader you will not be able to accomplish this, and anyhow, this is a very difficult task.
Option 1 - ELF manipulation
Each ELF executable is made from sections, which contain the actual code/data/symbol strings/... and segments which help the loader decide things like where to load your code in memory, which symbols this ELF exposes, which symbols it requires from other locations, where to load specific code/data, etc.
You can observe the segments in your binary by typing
readelf -l [your binary]
The output will be similiar to the following (I chose ls as the binary):
[ishaypeled#ishay-dev bin]$ readelf -l --wide ./ls
Elf file type is EXEC (Executable file)
Entry point 0x4048bf
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000400040 0x0000000000400040 0x0001f8 0x0001f8 R E 0x8
INTERP 0x000238 0x0000000000400238 0x0000000000400238 0x00001c 0x00001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x01b694 0x01b694 R E 0x200000
LOAD 0x01bdf0 0x000000000061bdf0 0x000000000061bdf0 0x000864 0x0016d0 RW 0x200000
DYNAMIC 0x01be08 0x000000000061be08 0x000000000061be08 0x0001f0 0x0001f0 RW 0x8
NOTE 0x000254 0x0000000000400254 0x0000000000400254 0x000044 0x000044 R 0x4
GNU_EH_FRAME 0x01895c 0x000000000041895c 0x000000000041895c 0x00071c 0x00071c R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x01bdf0 0x000000000061bdf0 0x000000000061bdf0 0x000210 0x000210 R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
08 .init_array .fini_array .jcr .dynamic .got
Now let's examine this output:
In the first table (Program Headers):
[Type] - Segment type, what is the purpose of this section
[Offset] - Offset in file where this segment begins
[VirtAddr] - Where we want to load this section in process address space (if this segment should be loaded at all, not all of them are loaded)
[PhysAddr] - Same as VirtAddr for all modern OS's I encountered
[FileSiz] - How big is this section on file. This is the link to your sections - the current segment consists of all sections in the range Offset to Offset+FileSiz
[MemSiz] - How big is this section in virtual memory (this does NOT have to be the same as the size on file! if it spans beyond the size in file the excess is set to 0)
[Flg] - Permission flags, R-read E-execute W-write.
[Align] - Required memory alignment in memory.
Your focus is on segments of type LOAD (PT_LOAD). These segments group data from sections, instruct the loader where to put them in the process address space and determine specify their permissions.
You can see a convenient section to segment mapping in the Section to Segment mapping table.
Lets observe the two LOAD segments 2 and 3:
We can see that segment 2 has read and execute permissions, and that it spans (among other) the .text and .rodata sections.
So, to achieve your purpose using ELF manipulation:
Locate the binary data that makes your functions in the file (readelf utility is your friend)
By modifying the ELF header (I don't know any tool that does this automatically, you'd probably have to write your own) split the segment containing .text section into two sequential LOAD segments, leaving out your function code
By modifying the ELF header create a new LOAD segment containing only your two functions
Update all references (if any) to the old function location to the new one
If you read up to here and understood everything, you should know this is a tremendously tedious, nearly impossible task for real life cases.
Option 2 - Dynamic linker manipulation
Note the INTERP segment type in the above example. This is an ASCII string that specifies which dynamic linker you should use.
The dynamic linker role is to parse the segments and perform all dynamic operations such as resolving symbols at runtime, loading segments from .so file, etc.
A possible manipulation here would be to modify the dynamic linker code (NOTE: this is a system wide change!) to load the functions binary data into a specific memory address in the process address space. Note that this approach has a couple of set backs:
It requires modification to the dynamic linker
You need to update all references to your functions within the ELF file still
Option 3 - Dynamic loader manipulation
Much like option 2, but modify the ld library facilities instead of the dynamic linker.
Conclusion
Exactly what you wish to do is very hard, and indeed a tedious task. I am working on a tool that allows injection of arbitrary functions into existing shared object files at the moment and I guarantee this to be at least a few good weeks of work.
Are you sure there isn't another way to achieve what you want? Why do you need these two functions in a separate address? Perhaps there is an easier solution...

Related

Why is .rela.plt necessary for resolving PIC function addresses?

While exploring ELF structure, I see this (this is objdump -d and readelf -r of the binary linked with a PIC .so containing ml_func):
0000000000400480 <_Z7ml_funcii#plt>:
400480: ff 25 92 0b 20 00 jmpq *0x200b92(%rip) # 601018 <_Z7ml_funcii>
Relocation section '.rela.plt' at offset 0x438 contains 1 entry:
Offset Info Type Sym. Value Sym. Name + Addend
000000601018 000100000007 R_X86_64_JUMP_SLO 0000000000000000 _Z7ml_funcii + 0
Isn't .rela.plt redundant? It seems to store the same offset 601018 which is already calculated at ml_func#plt.
Or is it useful for some more complex cases like different relocation types? Or is it just an optimization of some sort (like, I guess it might be not trivial to get the 601018 from outside the ml_func#plt...)?..
I guess this question is similar to Why does the linker generate seemingly useless relocations in .rela.plt?, where they write that
.rela.plt is used to resolve function addresses, even during lazy linking.
I guess I wonder why the resolver couldn't do its work without the .rela.plt.
The 601018 you see in .plt is not actually coming from that section. This is merely a helpful annotation which readelf is providing to you. readelf itself discovered this information by looking at .rela.plt.
When your program starts up, the global offset table (GOT) needs to contain an address inside the procedure linkage table (PLT) in order to bootstrap the dynamic linking logic. However, when your program is compiled, the compiler doesn't know yet know the absolute address of the PLT. That's why the .rela.plt section exists. The dynamic linker uses this information to patch the GOT when your program starts.

gcc: how to produce ELF where file size equals mem size for all LOAD segments without custom linker script?

I have to produce an ELF binary with gcc from a Hello World-program written in C, where the mem size equals the file size in all LOAD-segments of the ELF file. My experience says me, that I can prevent this if I move .bss into .data in a custom linker script. But in my case, I want to achieve this without a custom linker script.
Is there a way I can force all LOAD-segments to have the same file size as mem size with an option for GCC?
Background: I'm working on enabling Linux binaries on a custom OS. The ELF-Loader so far is pretty basic and testing/developing will be much simpler, if I just can map the ELF as it is (as long as all LOAD-segments are page-aligned)..
For completeness, I provide the solution that includes a dedicated linker script. The relevant excerpt is the following:
.data ALIGN(4K) :
{
*(.data .data.*)
/* Putting .bss into the .data segment simplifies loading an ELF file especially in kernel
scenarios. Some basic ELF loaders in OS dev space require MEMSIZE==FILESIZE for each
LOAD segment. The zeroed memory will land "as is" in the ELF and increase its size.
I'm not sure why but "*(COMMON)" must be specified as well so that the .bss section
actually lands in .data. But the GNU ld doc also does it like this:
https://sourceware.org/binutils/docs/ld/Input-Section-Common.html */
*(COMMON)
*(.bss .bss.*)
} : rw
It is important that the output section is not called ".bss" and that
the section contains more than just ".bss". Otherwise, the "FILESIZE != MEMSIZE" optimization is done where the ELF loader needs to provide zeroed memory.

GRUB Multiboot header not found

After reading this this question and it's primary answer, I ran readelf on my kernel, and noticed my .text section was at 0x00101000 and not 0x00100000. I also noticed a section above that read .not.gnu.build-i that was in the place the .text section is supposed to be. Is there a way I could make my .text section be in the correct place? I have already used align 4 to set it to 1M.
The issue is that LD (or LD via GCC) is automatically placing a notes section (if one was generated) in the first 4k. If linking the final kernel with GCC pass it the -Wl,--build-id=none option. If you are using LD directly to link the final binary then you can pass it --build-id=none .
If writing a multiboot ELF object the existence of this extra section can force the mulitboot header beyond the 8k position in the file. This is accounting for the fact that ELF headers usually take a minimum of the first 4k of the file. Add in the 4k for .note.gnu.build-id and .multiboot section is now beyond 8k mark of the physical file. This will cause a multiboot loader like GRUB to think your ELF executable doesn't have a multiboot header since it only looks through the first 8k of the file.
Your linker script (given that it is the same as in the other question) is the problem: By telling it to 4k-align the sections and putting multiboot in a separate section, you allocate 4k for it, so .text starts at an offset of 1M + 4k, which causes your problem. Change it to the following:
SECTIONS
{
. = 1M;
.text ALIGN(4K) :
{
*(.multiboot)
*(.text)
}
[snip]

How to prevent ld from combining writable and executable sections?

When I link together object files, the resulting ELF executable has (only) the following LOAD segment:
LOAD off 0x00000000 vaddr 0x00008000 paddr 0x00008000 align 2**15
filesz 0x000010f0 memsz 0x000010f0 flags rwx
The linker ld combined all sections into one rwx segment, instead of separating writable and executable parts. I want to prevent this. The relocatable objects have the sections marked as writable or executable as appropriate, so this problem appears at the link time.
So, what determines how ld assigns permissions to the segments? The linker script does not seem to have anything related to that. Is it something specified when the toolchain is built?
I am targeting the ARM, and the toolchain is arm-linux-gnueabi, binutils version 2.22.
Edit: The linker script is here. The other linker options are -Bdynamic, --gc-sections, -z nocopyreloc and --no-undefined.
Usually linker scripts are used to define sections, their order, whether to keep them or trash them from the binary (release build linker script might chose to remove debugging info).
Here is an example of a linker script:
system-onesegment.ld
EDIT: to modify section permission, put this before whatever section you want to change the permission of .section .section_name, "permission".
Example:
.text
mov r0, r0
b main
.section .rodata, "ro"
.word 0x00000001
.previous
main: mov r0, r0

How to get pointers and sizes of variables from the compiler - from outside the compiled code?

I'd like the compiler to output a file containing the pointers to all global variables in the source code it is compiling, and also the sizes of them.
Is this possible? Is there a way to do it in any c compiler?
Something like a map file? That will show where the globals and statics are allocated, but not what they point at. Most compilers (linkers) will output one automatically or with a simple statement. Just search for map file in your documentation.
This information is available in the symbol table of the binary, though it might not mean what you expect it to.
The compiler takes one or more source files, compiles the code to object code, and generates an object file (.o on Unix, .obj on Windows). All variables and functions referenced in the source file are mentioned in the symbol table. Variables and functions that are defined in the source file have specific addresses and sizes, while symbols not defined in the source file are marked as undefined and must be linked later. All symbols are listed relative to a particular section. Common sections are ".text" for executable code, ".bss" for variables that are initialized to zero when the program starts, and ".data" for variables initialized with non-zero values.
The linker takes one or more object files, combines the sections (putting all of code and data from each object file into one big section for code and data), and writes an output file. This output file may be an executable, or it may be a shared library. An executable on disk still doesn't have a pointer for each variable; it still stores the offset from the beginning of the section to the variable.
When an executable is run, the operating system's dynamic loader reads the executable, finds each section, and allocates memory for that section. (It may also set up different permissions on each section -- the ".text" segment is often marked as read-only, and (on processors that support it) data segments are sometimes marked as non-executable.) Only then does a variable get a pointer -- when the code needs to access a particular variable, it adds the address of the beginning of the section to the offset from the beginning of the section to get the pointer.
You can use various tools to investigate each binary's symbol table. The GNU toolchain's objdump (used on Linux) is one such tool.
For a simple C hello-world program:
#include <stdio.h>
const char message[] = "Hello world!\n";
int main(int argc, char ** argv) {
printf(message);
return 0;
}
I compile (but don't link) it on my Linux box:
$ gcc -c hello.c -o hello.o
Now I can look at the symbol table:
$ objdump -t hello.o
hello.o: file format elf32-i386
SYMBOL TABLE:
00000000 l df *ABS* 00000000 hello.c
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .rodata 00000000 .rodata
00000000 l d .note.GNU-stack 00000000 .note.GNU-stack
00000000 l d .comment 00000000 .comment
00000000 g O .rodata 0000000e message
00000000 g F .text 0000002b main
00000000 *UND* 00000000 puts
The first column is the address of each symbol, relative to the beginning of the section. Each symbol has various flags, and some of the symbols are used as hints to the rest of the toolchain and the debugger. (If I built with debugging symbols, I'd see many entries devoted to them as well.) My simple program has only one variable:
00000000 g O .rodata 0000000e message
The fifth column tells me the symbol message is size 0xe -- 14 bytes.
While no compiler is required to output this data, most linkers can dump out this information. For example, Microsoft's linker mapfile contains all the public symbols in an executable/dll as well as their address relative to the section (read only, read write, code, zero initialized, etc.) they are put in. Sizes can be derived from that, although it's mainly an approximation.
You can also probably figure out a way to inspect the debugging symbols generated for the executable, as that's exactly what a debugger has to do anyway.
Normally you'd get this from the linker, not the compiler -- the linker is what assigns addresses to things. Most linkers can produce a map file that will contain the addresses of global variables and functions (as well as any other symbols in the executable it creates). It'll be up to you to sort out which are which. All of them I've seen include something to tell you, but the exact format varies with the linker involved.

Resources