I'm attempting to create a custom linker script that takes all functions except main
and the internal startup functions and put them into a different segment named .text_enc
.
Sample code:
mod1.c:
#include <stdio.h>void foo(){ printf("in foo\n");}
main.c:
#include <stdio.h>void foo();int main(){ printf("in main\n"); foo(); return 0;}
To start with, I took the default linker script and added a part for the new section just before the part for .text
, explicitly specifying the module with the function to put in the new section:
.text_enc : { mod1.o(.text) } .text : { *(.text.unlikely .text.*_unlikely .text.unlikely.*) *(.text.exit .text.exit.*) *(.text.startup .text.startup.*) *(.text.hot .text.hot.*) *(.text .stub .text.* .gnu.linkonce.t.*) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) }
I compiled:
gcc -Wall -Wextra -c mystart.cgcc -Wall -Wextra -c mod1.cgcc -Wall -Wextra -o prog -T myenc1.ld mystart.o mod1.o
And the results were as expected with foo
residing in section .text_enc
:
[dbush@db-centos7 enc]$ objdump -t main.o | grep text0000000000000000 l d .text 0000000000000000 .text0000000000000000 g F .text 000000000000000a foo0000000000000010 g F .text 0000000000000057 enc_main[dbush@db-centos7 enc]$ objdump -t mod1.o | grep text0000000000000000 l d .text 0000000000000000 .text0000000000000000 g F .text 0000000000000010 foo[dbush@db-centos7 enc]$ objdump -t prog | grep text0000000000400440 l d .text_enc 0000000000000000 .text_enc0000000000400450 l d .text 0000000000000000 .text0000000000400480 l F .text 0000000000000000 deregister_tm_clones00000000004004b0 l F .text 0000000000000000 register_tm_clones00000000004004f0 l F .text 0000000000000000 __do_global_dtors_aux0000000000400510 l F .text 0000000000000000 frame_dummy00000000004005d0 g F .text 0000000000000002 __libc_csu_fini0000000000400560 g F .text 0000000000000065 __libc_csu_init0000000000400440 g F .text_enc 0000000000000010 foo0000000000400450 g F .text 0000000000000000 _start000000000040053d g F .text 000000000000001f main
In this simple example there is only one other source file besides the one with main
. A "real" example could have dozens of source files each with dozens of functions. I'd like to avoid listing each individual source file in the linker script. I'd like to instead tell the linker to put the code the file containing main
and the files with the system startup functions in .text
, and put the code in all other files in .text_enc
. That way I don't have to worry about keeping it up to date if source files are added or deleted, and I can use this script for multiple projects.
Using the -v
option to gcc, I saw that it included crt1.o, crti.o, and crtbegin.o in the link command (CentOS 7.2, gcc 4.8.5) which contained the startup related functions listed in the object dump. So I attempted to modify the linker script as follows:
.text : { mystart.o(.text) crt1.o(.text) crti.o(.text) crtbegin.o(.text) } .text_enc : { *(.text.unlikely .text.*_unlikely .text.unlikely.*) *(.text.exit .text.exit.*) *(.text.startup .text.startup.*) *(.text.hot .text.hot.*) *(.text .stub .text.* .gnu.linkonce.t.*) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) }
However the linking failed:
gcc -v -Wall -Wextra -o prog -T myenc2.ld mystart.o mod1.oUsing built-in specs.COLLECT_GCC=gccCOLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapperTarget: x86_64-redhat-linuxConfigured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linuxThread model: posixgcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) COMPILER_PATH=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/:/usr/lib/gcc/x86_64-redhat-linux/LIBRARY_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.8.5/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../:/lib/:/usr/lib/COLLECT_GCC_OPTIONS='-v''-Wall''-Wextra''-o''prog''-T''myenc2.ld''-mtune=generic''-march=x86-64' /usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o prog /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../.. mystart.o mod1.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o -T myenc2.ld/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o: In function `_start':(.text+0x0): multiple definition of `_start'/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o:(.text+0x0): first defined here/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o:(.rodata.cst4+0x0): multiple definition of `_IO_stdin_used'/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o:(.rodata.cst4+0x0): first defined here/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o: In function `data_start':(.data+0x0): multiple definition of `__data_start'/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o:(.data+0x0): first defined here/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o: In function `_init':(.init+0x0): multiple definition of `_init'/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o:(.init+0x0): first defined here/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o: In function `_fini':(.fini+0x0): multiple definition of `_fini'/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o:(.fini+0x0): first defined here/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o:(.rodata+0x0): multiple definition of `__dso_handle'/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o:(.rodata+0x0): first defined herecollect2: error: ld returned 1 exit statusmake: *** [prog] Error 1
It seems like this caused the startup files to get pulled in to the linker twice. So I tried passing -nostartfiles
to gcc, but there were missing dependencies:
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o: In function `_start':(.text+0x12): undefined reference to `__libc_csu_fini'/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o: In function `_start':(.text+0x19): undefined reference to `__libc_csu_init'/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o: In function `deregister_tm_clones':crtstuff.c:(.text+0x1): undefined reference to `__TMC_END__'/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o: In function `register_tm_clones':crtstuff.c:(.text+0x31): undefined reference to `__TMC_END__'/usr/bin/ld: prog: hidden symbol `__TMC_END__' isn't defined/usr/bin/ld: final link failed: Bad valuecollect2: error: ld returned 1 exit statusmake: *** [prog] Error 1
What's the proper way to set up the linker script to have all of the application .o files put their code in .text_enc
without having to explicitly call each of them out (besides the one with main
)?