c - 如何将文件指针从 c 传递给 asm 中的调用
问题描述
我在搞乱 nasm,在没有问题的情况下做了一个 hello world 之后,我虽然会尝试做一些 c 集成。
我正在使用 c 打开一个文件,然后我想使用为打开的文件返回的指针来处理文本。但是,当我用 rdi 中的指针调用 fgetc 时,我得到一个“没有这样的文件或目录”,然后是一个段错误。
我究竟做错了什么?
int64_t asmFunc(FILE* a, char* b);
int main()
{
int num;
FILE *fptr;
size_t line_buf_size = 0;
char *ret = malloc(100);
fptr = fopen("./test.txt","r");
if(fptr == NULL)
{
printf("Error!");
exit(1);
}
printf("%ld", asmFunc(fptr, ret));
return 0;
}
global asmFunc
section .text
extern fgetc
asmFunc:
call fgetc ; segfault occurs here.
(...)
ret
解决方案
asmFunc 的第一条指令也不是调用,但我删除了一些设置内容以供以后操作以使其更易于阅读。
好吧,这违背了 MCVE 的全部目的。您需要在简化后重新运行测试,以确保它仍然显示与完整版本相同的问题。但是对于这个答案,我假设您的设置没有破坏fptr
RDI 中的 arg 或修改 RSP。
asmFunc:
call fgetc ; segfault occurs here.
fptr
仍将在 RDI 中,您的调用者将其传递给它,因此对于int fgetc(FILE *fp)
.
所以大概fgetc
是段错误,因为你用未对齐的堆栈调用它。call
(在跳转到 之前它是 16 字节对齐的asmFunc
,但是你没有奇数的 push 或任何sub rsp, 8*n
)。glibc 的现代构建实际上确实依赖于 scanf 的 16 字节对齐(从不对齐 RSP 的函数调用时 glibc scanf 分段错误),因此很容易想象 fgetc 包含的代码也可以编译为movaps
在堆。
一旦你修复了这个错误,你就会遇到call fgetc
破坏你的char *ret
arg 的问题,因为你的调用者在 RSI 中传递了它。 传递参数的寄存器是 call-clobbered。 通过 linux x86-64 函数调用保留了哪些寄存器
asmFunc: ; (FILE *fptr, char *ret)
push rsi ; save ret
call fgetc
pop rsi
mov [rsi], al
ret
AC 编译器通常会保存/恢复 RBX 并用于mov
保存ret
那里。
asmFunc: ; (FILE *fptr, char *ret)
push rbx
mov rbx, rsi ; save ret
call fgetc
mov [rbx], al
pop rbx ; restore rbx
ret
但是,当我用 rdi 中的指针调用 fgetc 时,我得到一个“没有这样的文件或目录”,然后是一个段错误。
不知道你是如何得到“没有这样的文件或目录”的。那是从您的调试器中寻找 glibc 函数的源代码吗?如果它是您的程序本身打印的内容的一部分,那几乎是零意义,因为您exit(1)
在 fptr == NULL
. 而且您不使用perror()
或任何其他查找 errno 代码来生成标准错误字符串的东西。
推荐阅读
- python - 元组对象不是可调用问题。(简单鳕鱼)
- python - Scrapy在身份验证后抓取每个链接
- mysql - 如何针对数组在表中搜索json编码的数组列并返回匹配结果?
- java - 基于字符偏移的动态重新定位的字符阅读器(如 FileReader)
- javascript - JavaScript 日期元素显示为第二天而不是当天
- excel - 将数据从 excel 复制到现有的 powerpoint 图表
- javascript - 使用 .select jquery 但没有得到任何选定的文本
- javascript - HTML5 直接从 Safari iOS 上的照片库中选择照片
- python - Python中的df_dict
- kivy - 在 RecyleView kivy 中添加 KivyMD 扩展面板