使用 AT&T 语法从另一个共享库调用 libc 函数?
Calling libc functions from another shared library in AT&T syntax?
我正在尝试 assemble 通过 gcc 将下面的代码添加到共享库。
.section .text
.global S_0x400607
.type S_0x400607, @function
S_0x400607:
push %rbp
mov %rsp,%rbp
sub [=10=]x10,%rsp
mov %edi,-0x4(%rbp)
mov -0x4(%rbp),%eax
mov %eax,%esi
lea S_0x400724(%rip),%rdi
mov [=10=]x0,%eax
callq printf
nop
leaveq
retq
.section .rodata
S_0x400724:
.byte 0x25
.byte 0x64
.byte 0x0a
.byte 0x00
我在终端中使用了下面的命令但出现了错误。
$ gcc zzz_out.s -shared -fPIC -o libzzz.so
/usr/bin/ld: /tmp/ccq8FvIT.o: relocation R_X86_64_PC32 against symbol `printf@@GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
然后我用谷歌搜索了这个问题,在 中得到了一个看似可行的答案。然后我添加了选项 -no-pie
,使用了下面的命令并得到了另一个错误。
$ gcc zzz_out.s -shared -fPIC -no-pie -o libzzz.so
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
看来选项的顺序很重要。但是我使用了这样的 32 位代码。
.section .text
.globl S_0x8048506
.type S_0x8048506, @function
S_0x8048506:
push %ebp
mov %esp,%ebp
push %ebx
sub [=13=]x4,%esp
call S_0x80485CC
add $_GLOBAL_OFFSET_TABLE_,%eax
sub [=13=]x8,%esp
pushl 0x8(%ebp)
lea S_0x8048670,%edx
push %edx
mov %eax,%ebx
call printf
add [=13=]x10,%esp
nop
mov -0x4(%ebp),%ebx
leave
ret
S_0x80485CC:
mov (%esp),%eax
ret
.section .rodata
S_0x8048670:
.byte 0x25
.byte 0x64
.byte 0x0a
.byte 0x00
gcc 完美运行,libzzz.so
在当前目录中生成。
对不起,如果我问了一个简单的问题。我是这个地区的新手。
你只有 undefined reference to `main'
和 -no-pie
。
我认为 -no-pie
覆盖了 -shared
,所以你告诉 GCC link 一个 position-dependent 可执行文件 ,根本不是 shared-library。 (ELF 共享库又名“共享对象”始终必须是 position-independent,没有 non-PIC .so
这样的东西。有趣的事实:PIE 可执行文件是另一种类型的 ELF 共享对象。)
与 linking non-PIE 可执行文件不同,ld
通过 PLT 为您重写 call printf
为调用。但是当 link 使用 PIE 或共享库时,您必须手动执行。 (较新的 ld
可能会为您做到这一点,至少在 PIE 中是这样,但这是最近的更改。)
在 32 位代码中,call printf
可能会汇编并 links 使用运行时修复程序在运行时重写 call rel32
指令成为 printf
在 libc 中的实际地址,一旦它被加载到一个随机的基地址。但这不适用于 64 位代码,因为它可能超过 +-2GiB。类似于 32-bit absolute addresses no longer allowed in x86-64 Linux? 在发行版将 PIE 可执行文件设为默认 GCC 配置后的原因。
您的 64 位代码选项是:
call *printf@GOTPCREL(%rip)
,就像 gcc -fno-plt
在编译 C 时会发出。
call printf@plt
就像编译器历史上使用的那样。
- non-PIE 可执行文件不是一个选项;你正在制作一个
-shared
库。
有关此的 NASM-syntax 版本的更多详细信息,以及机器代码,请参阅 。底部还有一些示例,其中包括 AT&T 语法,如果您执行 call *foobar@GOTPCREL(%rip)
,linker 如何将其“放松”为 call rel32
,然后 foobar
定义在毕竟是同一个共享库(具有“隐藏”可见性,不是全局的,因此不需要符号插入)。
有关 PIE 与 non-PIE 可执行文件的编译器输出的一些示例,请参见 (PIE 可执行代码也可以在共享库中运行。)
-fno-plt
风格的 code-gen 在 32 位模式下可能不值得,在这种模式下你没有有效的 EIP-relative 寻址来到达 GOT,除非你已经需要此函数中其他内容的 GOT 指针。
我正在尝试 assemble 通过 gcc 将下面的代码添加到共享库。
.section .text
.global S_0x400607
.type S_0x400607, @function
S_0x400607:
push %rbp
mov %rsp,%rbp
sub [=10=]x10,%rsp
mov %edi,-0x4(%rbp)
mov -0x4(%rbp),%eax
mov %eax,%esi
lea S_0x400724(%rip),%rdi
mov [=10=]x0,%eax
callq printf
nop
leaveq
retq
.section .rodata
S_0x400724:
.byte 0x25
.byte 0x64
.byte 0x0a
.byte 0x00
我在终端中使用了下面的命令但出现了错误。
$ gcc zzz_out.s -shared -fPIC -o libzzz.so
/usr/bin/ld: /tmp/ccq8FvIT.o: relocation R_X86_64_PC32 against symbol `printf@@GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
然后我用谷歌搜索了这个问题,在 -no-pie
,使用了下面的命令并得到了另一个错误。
$ gcc zzz_out.s -shared -fPIC -no-pie -o libzzz.so
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
看来选项的顺序很重要。但是我使用了这样的 32 位代码。
.section .text
.globl S_0x8048506
.type S_0x8048506, @function
S_0x8048506:
push %ebp
mov %esp,%ebp
push %ebx
sub [=13=]x4,%esp
call S_0x80485CC
add $_GLOBAL_OFFSET_TABLE_,%eax
sub [=13=]x8,%esp
pushl 0x8(%ebp)
lea S_0x8048670,%edx
push %edx
mov %eax,%ebx
call printf
add [=13=]x10,%esp
nop
mov -0x4(%ebp),%ebx
leave
ret
S_0x80485CC:
mov (%esp),%eax
ret
.section .rodata
S_0x8048670:
.byte 0x25
.byte 0x64
.byte 0x0a
.byte 0x00
gcc 完美运行,libzzz.so
在当前目录中生成。
对不起,如果我问了一个简单的问题。我是这个地区的新手。
你只有 undefined reference to `main'
和 -no-pie
。
我认为 -no-pie
覆盖了 -shared
,所以你告诉 GCC link 一个 position-dependent 可执行文件 ,根本不是 shared-library。 (ELF 共享库又名“共享对象”始终必须是 position-independent,没有 non-PIC .so
这样的东西。有趣的事实:PIE 可执行文件是另一种类型的 ELF 共享对象。)
与 linking non-PIE 可执行文件不同,ld
通过 PLT 为您重写 call printf
为调用。但是当 link 使用 PIE 或共享库时,您必须手动执行。 (较新的 ld
可能会为您做到这一点,至少在 PIE 中是这样,但这是最近的更改。)
在 32 位代码中,call printf
可能会汇编并 links 使用运行时修复程序在运行时重写 call rel32
指令成为 printf
在 libc 中的实际地址,一旦它被加载到一个随机的基地址。但这不适用于 64 位代码,因为它可能超过 +-2GiB。类似于 32-bit absolute addresses no longer allowed in x86-64 Linux? 在发行版将 PIE 可执行文件设为默认 GCC 配置后的原因。
您的 64 位代码选项是:
call *printf@GOTPCREL(%rip)
,就像gcc -fno-plt
在编译 C 时会发出。call printf@plt
就像编译器历史上使用的那样。- non-PIE 可执行文件不是一个选项;你正在制作一个
-shared
库。
有关此的 NASM-syntax 版本的更多详细信息,以及机器代码,请参阅 call *foobar@GOTPCREL(%rip)
,linker 如何将其“放松”为 call rel32
,然后 foobar
定义在毕竟是同一个共享库(具有“隐藏”可见性,不是全局的,因此不需要符号插入)。
有关 PIE 与 non-PIE 可执行文件的编译器输出的一些示例,请参见
-fno-plt
风格的 code-gen 在 32 位模式下可能不值得,在这种模式下你没有有效的 EIP-relative 寻址来到达 GOT,除非你已经需要此函数中其他内容的 GOT 指针。