将非启动模块默认为自定义链接器脚本中的新部分
Defaulting non-startup modules to new section in custom linker script
我正在尝试创建一个自定义 linker 脚本,它采用除 main
和内部启动函数之外的所有函数,并将它们放入名为 .text_enc
的不同段中。
示例代码:
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;
}
首先,我采用了默认的 linker 脚本,并在 .text
的部分之前为新部分添加了一个部分,明确指定了具有要放入的函数的模块新部分:
.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)
}
我编译:
gcc -Wall -Wextra -c mystart.c
gcc -Wall -Wextra -c mod1.c
gcc -Wall -Wextra -o prog -T myenc1.ld mystart.o mod1.o
结果与预期的一样,foo
位于 .text_enc
部分:
[dbush@db-centos7 enc]$ objdump -t main.o | grep text
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 g F .text 000000000000000a foo
0000000000000010 g F .text 0000000000000057 enc_main
[dbush@db-centos7 enc]$ objdump -t mod1.o | grep text
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 g F .text 0000000000000010 foo
[dbush@db-centos7 enc]$ objdump -t prog | grep text
0000000000400440 l d .text_enc 0000000000000000 .text_enc
0000000000400450 l d .text 0000000000000000 .text
0000000000400480 l F .text 0000000000000000 deregister_tm_clones
00000000004004b0 l F .text 0000000000000000 register_tm_clones
00000000004004f0 l F .text 0000000000000000 __do_global_dtors_aux
0000000000400510 l F .text 0000000000000000 frame_dummy
00000000004005d0 g F .text 0000000000000002 __libc_csu_fini
0000000000400560 g F .text 0000000000000065 __libc_csu_init
0000000000400440 g F .text_enc 0000000000000010 foo
0000000000400450 g F .text 0000000000000000 _start
000000000040053d g F .text 000000000000001f main
在这个简单的例子中,除了带 main
的源文件之外,只有一个其他源文件。一个“真实”的例子可能有几十个源文件,每个源文件都有几十个函数。我想避免在 linker 脚本中列出每个单独的源文件。我想改为告诉 linker 将包含 main
的文件和具有系统启动功能的文件的代码放在 .text
中,并将所有其他文件中的代码放在.text_enc
。这样,如果添加或删除源文件,我就不必担心保持最新,并且我可以将此脚本用于多个项目。
使用 gcc 的 -v
选项,我看到它在 link 命令中包含 crt1.o、crti.o 和 crtbegin.o(CentOS 7.2 , gcc 4.8.5),其中包含对象转储中列出的与启动相关的函数。所以我尝试修改 linker 脚本如下:
.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)
}
但是 linking 失败了:
gcc -v -Wall -Wextra -o prog -T myenc2.ld mystart.o mod1.o
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-redhat-linux
Configured 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-linux
Thread model: posix
gcc 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 here
collect2: error: ld returned 1 exit status
make: *** [prog] Error 1
这似乎导致启动文件被拉入 linker 两次。所以我尝试将 -nostartfiles
传递给 gcc,但是缺少依赖项:
/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 value
collect2: error: ld returned 1 exit status
make: *** [prog] Error 1
设置 linker 脚本以使所有应用程序 .o 文件将它们的代码放入 .text_enc
而不必显式调用它们中的每一个(除了一个 main
)?
我设法弄明白了。我没有调用 .text
部分中的自动链接文件,导致它们被链接两次,而是在 .text_enc
部分中使用 EXCLUDE_FILE
。
.text_enc : {
*(EXCLUDE_FILE (*/crt1.o */crti.o */crtbegin.o */crtend.o */libc_nonshared.a mystart.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)
}
所以我可以保留原来的 .text
部分不变,只是在上面添加了 .text_enc
以及要排除的文件。这提供了与我最初尝试相同的结果,我最初尝试明确列出要包含在 .text_enc
中的文件,并且无需采取任何措施来防止双重链接。
我正在尝试创建一个自定义 linker 脚本,它采用除 main
和内部启动函数之外的所有函数,并将它们放入名为 .text_enc
的不同段中。
示例代码:
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;
}
首先,我采用了默认的 linker 脚本,并在 .text
的部分之前为新部分添加了一个部分,明确指定了具有要放入的函数的模块新部分:
.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)
}
我编译:
gcc -Wall -Wextra -c mystart.c
gcc -Wall -Wextra -c mod1.c
gcc -Wall -Wextra -o prog -T myenc1.ld mystart.o mod1.o
结果与预期的一样,foo
位于 .text_enc
部分:
[dbush@db-centos7 enc]$ objdump -t main.o | grep text
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 g F .text 000000000000000a foo
0000000000000010 g F .text 0000000000000057 enc_main
[dbush@db-centos7 enc]$ objdump -t mod1.o | grep text
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 g F .text 0000000000000010 foo
[dbush@db-centos7 enc]$ objdump -t prog | grep text
0000000000400440 l d .text_enc 0000000000000000 .text_enc
0000000000400450 l d .text 0000000000000000 .text
0000000000400480 l F .text 0000000000000000 deregister_tm_clones
00000000004004b0 l F .text 0000000000000000 register_tm_clones
00000000004004f0 l F .text 0000000000000000 __do_global_dtors_aux
0000000000400510 l F .text 0000000000000000 frame_dummy
00000000004005d0 g F .text 0000000000000002 __libc_csu_fini
0000000000400560 g F .text 0000000000000065 __libc_csu_init
0000000000400440 g F .text_enc 0000000000000010 foo
0000000000400450 g F .text 0000000000000000 _start
000000000040053d g F .text 000000000000001f main
在这个简单的例子中,除了带 main
的源文件之外,只有一个其他源文件。一个“真实”的例子可能有几十个源文件,每个源文件都有几十个函数。我想避免在 linker 脚本中列出每个单独的源文件。我想改为告诉 linker 将包含 main
的文件和具有系统启动功能的文件的代码放在 .text
中,并将所有其他文件中的代码放在.text_enc
。这样,如果添加或删除源文件,我就不必担心保持最新,并且我可以将此脚本用于多个项目。
使用 gcc 的 -v
选项,我看到它在 link 命令中包含 crt1.o、crti.o 和 crtbegin.o(CentOS 7.2 , gcc 4.8.5),其中包含对象转储中列出的与启动相关的函数。所以我尝试修改 linker 脚本如下:
.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)
}
但是 linking 失败了:
gcc -v -Wall -Wextra -o prog -T myenc2.ld mystart.o mod1.o
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-redhat-linux
Configured 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-linux
Thread model: posix
gcc 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 here
collect2: error: ld returned 1 exit status
make: *** [prog] Error 1
这似乎导致启动文件被拉入 linker 两次。所以我尝试将 -nostartfiles
传递给 gcc,但是缺少依赖项:
/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 value
collect2: error: ld returned 1 exit status
make: *** [prog] Error 1
设置 linker 脚本以使所有应用程序 .o 文件将它们的代码放入 .text_enc
而不必显式调用它们中的每一个(除了一个 main
)?
我设法弄明白了。我没有调用 .text
部分中的自动链接文件,导致它们被链接两次,而是在 .text_enc
部分中使用 EXCLUDE_FILE
。
.text_enc : {
*(EXCLUDE_FILE (*/crt1.o */crti.o */crtbegin.o */crtend.o */libc_nonshared.a mystart.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)
}
所以我可以保留原来的 .text
部分不变,只是在上面添加了 .text_enc
以及要排除的文件。这提供了与我最初尝试相同的结果,我最初尝试明确列出要包含在 .text_enc
中的文件,并且无需采取任何措施来防止双重链接。