0

在Igor Zhirkov 的《低级编程》一书中,有一个自定义共享库函数(“libfun”)的 got/plt 示例。

请参阅下面的原始 c 代码。

在书中,他表明在反汇编中,对 libfun 的调用转到 got/plt :

0000000000400580 <libfun@plt>:
jmp    QWORD PTR [rip+0x200a92]        # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
push   0x0
jmp    400570 <_init+0x20>

但在我的情况下,甚至没有使用 got/plt。我直接跳到 libfun 实现,objdump -D -Mintel-mnemonic main

0000000000001050 <libfun@plt>:
endbr64 
bnd jmp QWORD PTR [rip+0x2f75]        # 3fd0 <libfun>
nop    DWORD PTR [rax+rax*1+0x0]

为什么我没有任何 got/plt 用于 libfun ?

我的动态库创建有问题吗?国旗不见了?

当然,对于 printf 调用,got/plt 可以正常工作。第一次解析 printf 地址(推 0,jmp 到动态链接器...),第二次直接跳转到 printf 地址。

编码 :

主库.c:

extern void libfun( int value );

int global1 = 100;

int main( void ) {
    libfun( 42 );
    libfun( 24 );
    return 0;
}

dynlib.c:

#include <stdio.h>

extern int global1;
void libfun(int value) {
    printf( "param: %d\n", value );
    printf( "global: %d\n", global1 );
}

编译和链接:

gcc -c -o mainlib.o mainlib.c -g
gcc -c -fPIC -o dynlib.o dynlib.c
gcc -o dynlib.so -shared dynlib.o
gcc -o main mainlib.o dynlib.so

编辑 :

使用类似的程序,这次在汇编中,got/plt 按预期工作:

0000000000401010 <sofun@plt>:
  401010:   ff 25 02 20 00 00       jmp    QWORD PTR [rip+0x2002]        # 403018 <sofun>
  401016:   68 00 00 00 00          push   0x0
  40101b:   e9 e0 ff ff ff          jmp    401000 <.plt>

编码 :

主.asm:

extern _GLOBAL_OFFSET_TABLE_
global _start
extern sofun 

section .text
_start:
call sofun wrt ..plt
call sofun wrt ..plt ; 2nd time jumps to sofun implementation

; `exit` system call
mov rdi, 0
mov rax, 60
syscall

lib.asm:

extern _GLOBAL_OFFSET_TABLE_
global sofun:function

section .rodata
msg: db "SO function called", 10  
.end:

section .text
sofun:
mov rax, 1
mov rdi, 1
lea rsi, [rel msg]
mov rdx, msg.end - msg
syscall
ret

编译:

nasm -felf64 main.asm -o main.o -g -F dwarf
nasm -felf64 lib.asm -o lib.o
ld -shared lib.o -o lib.so
ld --dynamic-linker=/lib64/ld-linux-x86-64.so.2 main.o lib.so -o main

编辑 2:

回到c程序。这次用“no-pie”编译:gcc -o main -no-pie mainlib.o dynlib.so

现在它起作用了。 gdb main

0x401143 <main+13>      call   0x401040 <libfun@plt>
0x401040 <libfun@plt>           endbr64
0x401044 <libfun@plt+4>         bnd jmp QWORD PTR [rip+0x2fcd]        # 0x404018 <libfun@got.plt>
0x401030                            endbr64
0x401034                            push   0x0
0x401039                            bnd jmp 0x401020
0x401020                            push   QWORD PTR [rip+0x2fe2]        # 0x404008
0x401026                            bnd jmp QWORD PTR [rip+0x2fe3]        # 0x404010
0x7ffff7fe7bb0      endbr64 
0x7ffff7fe7bb4      push   rbx
... (job of dynamic linker)

第二个 libfun 调用(直接跳转到 libfun 实现):

0x40114d <main+23>              call   0x401040 <libfun@plt>
0x401040 <libfun@plt>           endbr64
0x401044 <libfun@plt+4>         bnd jmp QWORD PTR [rip+0x2fcd]        # 0x404018 <libfun@got.plt>
0x7ffff7fc5119 <libfun>         endbr64   
0x7ffff7fc511d <libfun+4>       push   rbp

所以,主要问题是:

使用 PIE(即没有 -no-pie),编译器如何知道在第一次调用库函数时在哪里解析它? gcc -o main mainlib.o dynlib.so

0x555555555156 <main+13>        call   0x555555555050 <libfun@plt>
0x555555555050 <libfun@plt>     endbr64
0x555555555054 <libfun@plt+4>   bnd jmp QWORD PTR [rip+0x2f75]        # 0x555555557fd0 <libfun@got.plt>
0x7ffff7fc5119 <libfun>         endbr64
0x7ffff7fc511d <libfun+4>       push   rbp
4

0 回答 0