我正在尝试通过Linux环境下的syscall
指令在一台x86_64机器上调用sys_write
,其中包含C文件中的内联汇编。为此,我编写了以下代码:
[tjm@ArchPad poc]$ cat poc.c
const char S[] = "abcd\n";
int main() {
__asm __volatile(" \
movq $1, %%rax; \
movq $1, %%rdi; \
movq %0, %%rsi; \
movq $5, %%rdx; \
syscall;"
:
: "i"(S)
);
return 0;
}
当我和GCC一起编译的时候,出现了以下错误:
[tjm@ArchPad poc]$ gcc -O0 poc.c -o poc
/usr/bin/ld: /tmp/ccWYxmSb.o: relocation R_X86_64_32S against symbol `S' can not be used when making a PIE object; recompile with -fPIE
collect2: error: ld returned 1 exit status
然后,我将-fPIE
添加到编译器命令中。不幸的是,一切都没有改变:
[tjm@ArchPad poc]$ gcc -fPIE -O0 poc.c -o poc
/usr/bin/ld: /tmp/ccdK36lx.o: relocation R_X86_64_32S against symbol `S' can not be used when making a PIE object; recompile with -fPIE
collect2: error: ld returned 1 exit status
这非常奇怪,这让我好奇地想手动编译和链接它:
[tjm@ArchPad poc]$ gcc -fPIE -O0 poc.c -S
[tjm@ArchPad poc]$ as -O0 poc.s -o poc.o
[tjm@ArchPad poc]$ ld -O0 -melf_x86_64 --dynamic-linker /usr/lib/ld-linux-x86-64.so.2 /usr/lib/crt{1,i,n}.o -lc poc.o -o poc
令人惊讶的是,在上面的尝试过程中没有发生错误。然后我测试了可执行文件的功能,这似乎是有效的:
[tjm@ArchPad poc]$ ./poc
abcd
有没有想过为什么会发生这种情况,以及如何防止GCC推广上面的错误?
发布于 2021-05-15 16:55:27
立即移动指令movq $S, %rsi
尽管采用64位寄存器,但仅采用32位带符号立即数。在构建与位置无关的可执行文件并使用ASLR运行时(这是大多数Linux系统上的默认设置),您的程序通常不位于虚拟内存的低或高31位中,因此像S
这样的全局或静态对象的地址不适合有符号的32位立即数。
一种修复方法是使用movabs
,它需要完整的64位立即数。用movabs %0, %%rsi
替换movq %0, %%rsi
可以构建代码。但是,更好的方法是使用RIP-relative addressing lea S(%rip), %rsi
,这是一条较短的指令,避免了在加载时重新定位的需要。在内联asm中做这件事有点笨拙,所以你可以让编译器用"S" (S)
这样的输入操作数为你加载地址到寄存器中(令人困惑的是,rsi
寄存器的约束是S
,它恰好与你为数组变量选择的名称一致)。
当您手动链接时,您构建了一个非位置独立的可执行文件,这意味着将地址视为常量是有效的。通过将-no-pie
传递给gcc
,也可以获得相同的效果。
您的代码还有另一个严重的问题,因为它没有声明它遇到的寄存器--不仅是显式mov
到的寄存器,还包括syscall
隐式修改的rcx
和r11
。你应该看看How to invoke a system call via syscall or sysenter in inline assembly?,它有一个正确的例子。仔细研究这些例子是明智的-- GCC内联asm功能强大,但也很容易以编译器无法帮助你检测的微妙方式出错,可能在简单的程序中看起来有效,但在更复杂的程序中却无法预测地失败。
发布于 2021-05-15 14:50:15
对于ASM指令,GCC支持多种方言,默认值可能会有所不同。点击此处阅读更多信息:
https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Extended-Asm
..。当然,这些方言彼此并不兼容。
https://stackoverflow.com/questions/67545995
复制