作为一个学校项目,我被要求重写 x86-64 程序集中的 write 函数。这个项目有一些规则。例如,正如 write 在发生错误时设置 errno 一样,我的 write 函数也应该以相同的方式设置 errno。另外,禁止使用 gcc 的
-no-pie
选项进行编译和链接。在 Linux 中,我们必须使用 errno.h 库中的 __errno_location
函数设置 errno 变量。所以我在我的汇编源文件中调用这个函数,并根据所需的规则进行设置。然后我在我的 main.c
源文件中声明它以使用我的 write 函数并用它来测试它。然后我输入编译和链接操作命令进行链接过程,但链接时遇到问题;
/usr/bin/ld: my_write.o: warning: relocation against `__errno_location@@GLIBC_2.2.5' in read-only section `.text'
/usr/bin/ld: my_write.o: relocation R_X86_64_PC32 against symbol `__errno_location@@GLIBC_2.2.5' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status
编译器告诉我使用
-fPIE
选项重新编译。但是当我再次执行时,它会给出相同的错误消息。
如果我使用
-no-pie
选项编译,这次会编译,但这也违反规则
有什么想法吗?
下面我分享一下文件内容以及我的编译步骤;
my_write.s;
section .text
global my_write
extern __errno_location
my_write:
mov rax, 1
syscall
cmp rax, -1
je err
ret
err:
neg rax
mov rdi, rax
call __errno_location
mov [rax], rdi
mov rax, -1
ret
main.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
extern ssize_t my_write(int fd, const void *buf, size_t count);
int main(void)
{
char *str = "Hello";
my_write(1, str, 5);
}
编译和链接
1.
nasm -felf64 -o my_write.o my_write.s
gcc -o test main.c my_write.o
/usr/bin/ld: my_write.o: warning: relocation against `__errno_location@@GLIBC_2.2.5' in read-only section `.text'
/usr/bin/ld: my_write.o: relocation R_X86_64_PC32 against symbol `__errno_location@@GLIBC_2.2.5' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status
给我一个这个错误。
您需要在 asm 代码中使用 PIE 兼容的调用:
call __errno_location@PLT
一般来说,对于PIE,在不同的.so中调用符号时,需要
@PLT