鉴于
main.c
:
#include <stdio.h>
void (*fn_ptr)(void);
void foo(void);
void bar(void) {
printf("bar\n");
}
int main(void) {
fn_ptr = bar;
foo();
}
和
foo.s
:
extern fn_ptr
global foo
foo:
mov rax, fn_ptr
call [rax]
ret
我们可以像这样运行和编译它:
clear &&
nasm foo.s -f elf64 -O0 &&
clang main.c foo.o -z noexecstack &&
./a.out
成功打印
bar
,但也打印警告:
/usr/bin/ld: foo.o: warning: relocation against `fn_ptr' in read-only section `.text'
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
bar
我在NASM中找不到任何调用全局函数指针的在线示例,将其更改为
mov rax, fn_ptr wrt ..plt
或call [fn_ptr wrt ..plt]
会打印此错误:
foo.s:7: error: ELF format cannot produce non-PC-relative PLT references
(对于任何想知道
-z noexecstack
消除了什么警告的人):
/usr/bin/ld: warning: foo.o: missing .note.GNU-stack section implies executable stack
/usr/bin/ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker
来自评论;我现在可以输入答案了。
以下组装说明不起作用:
mov rax, fn_ptr wrt ..plt
call fn_ptr wrt ..plt
call [fn_ptr wrt ..plt]
但这些确实:
lea rax, [rel fn_ptr wrt ..plt]
call [rel fn_ptr wrt ..plt]
确实存在ELF格式错误。我很惊讶它无法处理
mov rax, fn_ptr wrt ..plt
但 call [fn_ptr wrt ..plt]
肯定无法工作。没有call qword
这样的指令,只有call rel dword
和call [rel dword]
。