[英]How pass a file pointer from c to a call in 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 的全部目的。 您需要在簡化后重新運行您的測試,以確保它仍然顯示與您的完整版本相同的問題。 但是對於這個答案,我假設您的設置沒有破壞 RDI 中的fptr
arg 或修改 RSP。
asmFunc:
call fgetc ; segfault occurs here.
fptr
仍將在 RDI 中,您的調用者通過它,所以這對於int fgetc(FILE *fp)
是正確的。
所以大概fgetc
是段錯誤,因為你用一個未對齊的堆棧調用它。 (在跳轉到asmFunc
的call
之前它是 16 字節對齊的,但是您沒有奇數次推送或任何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 函數的源代碼嗎? 如果它是您的程序本身打印內容的一部分,那么這幾乎為零,因為您在fptr == NULL
時正確執行exit(1)
。 並且您不使用perror()
或任何其他查找 errno 代碼的方法來生成標准錯誤字符串。
您需要學習並遵循Linux x86-64 ABI規范中記錄的調用約定,特別是其§3.2.3 參數傳遞部分。 所以指針值fptr
在%rdi
,指針值ret
在%rsi
,你可能應該為你的asmFunc
推送一個調用幀
另請閱讀x86 調用約定wikipage。
如果您能夠在某些example.c
文件asmFunc
C 編寫等效的(甚至是簡化的) asmFunc
,我建議使用gcc -O -fverbose-asm -Wall -S example.c
編譯它並查看發出的example.s
匯編程序文件以獲得靈感。 大多數情況下,此類函數的第一條機器指令不是call
(而是某種稱為函數序言、更改堆棧指針%esp
並在調用堆棧上分配一些調用幀的東西)
例如,在我的 Linux/Debian/x86-64 上使用 gcc-8
void asmfunc(FILE* fil, char*s) {
fputc ('\t', fil);
fputs (s, fil);
fputc ('\n', fil);
fflush (fil);
}
編譯成:
.text
.globl asmfunc
.type asmfunc, @function
asmfunc:
.LFB11:
.cfi_startproc
pushq %rbp #
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
pushq %rbx #
.cfi_def_cfa_offset 24
.cfi_offset 3, -24
subq $8, %rsp #,
.cfi_def_cfa_offset 32
movq %rdi, %rbx # fil, fil
movq %rsi, %rbp # s, s
# /tmp/example.c:4: fputc ('\t', fil);
movq %rdi, %rsi # fil,
movl $9, %edi #,
call fputc@PLT #
# /tmp/example.c:5: fputs (s, fil);
movq %rbx, %rsi # fil,
movq %rbp, %rdi # s,
call fputs@PLT #
# /tmp/example.c:6: fputc ('\n', fil);
movq %rbx, %rsi # fil,
movl $10, %edi #,
call fputc@PLT #
# /tmp/example.c:7: fflush (fil);
movq %rbx, %rdi # fil,
call fflush@PLT #
# /tmp/example.c:8: }
addq $8, %rsp #,
.cfi_def_cfa_offset 24
popq %rbx #
.cfi_def_cfa_offset 16
popq %rbp #
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE11:
.size asmfunc, .-asmfunc
.ident "GCC: (Debian 8.3.0-6) 8.3.0"
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.