Quantcast
Viewing all articles
Browse latest Browse all 22104

Defaulting non-startup modules to new section in custom linker script

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)?


Viewing all articles
Browse latest Browse all 22104


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>