Linux 从 c 调用汇编函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4676587/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
calling assembly functions from c
提问by
I'm trying to use a function in assembly, invoked from a C project. This function is supposed to call a libc function let's say printf()
, but I keep getting a segmentation fault.
我正在尝试在程序集中使用从 C 项目调用的函数。这个函数应该调用一个 libc 函数,比方说printf()
,但我一直收到分段错误。
In the .c file I have the declaration of the function let's say
在 .c 文件中我有函数的声明让我们说
int do_shit_in_asm()
In the .asm file I have
在 .asm 文件中我有
.extern printf
.section .data
printtext:
.ascii "test"
.section .text
.global do_shit_in_asm
.type do_shit_in_asm, @function
do_shit_in_asm:
pushl %ebp
movl %esp, %ebp
push printtext
call printf
movl %ebp, %esp
pop %ebp
ret
Any pointerscomments would be appreciated.
任何指针评论将不胜感激。
as func.asm -o func.o
gcc prog.c func.o -o prog
采纳答案by R.. GitHub STOP HELPING ICE
Change push printtext
to push $printtext
.
更改push printtext
为push $printtext
。
As it is, you're loading a value from the address printtext
and pushing that, rather than pushing the address. Thus, you're passing 'test'
as a 32-bit number, rather than a pointer, and printf
is trying to interpret that as an address and crashing.
实际上,您正在从地址加载一个值printtext
并推送它,而不是推送地址。因此,您传递的'test'
是 32 位数字,而不是指针,并printf
试图将其解释为地址并崩溃。
回答by Greg Hewgill
One of the best ways to get started with assembly language functions is to write a similar function in C, and then build it with the compiler switch that generates an assembly listing (-S
on gcc). Then you can study the output of what the compiler did, and modify as needed.
开始使用汇编语言函数的最好方法之一是用 C 编写一个类似的函数,然后使用生成汇编列表(-S
在 gcc 上)的编译器开关构建它。然后你可以研究编译器所做的输出,并根据需要进行修改。
This is particularly useful if you're calling functions such as printf
which use a different calling convention (because of the variable number of arguments). Calling those functions may be quite different from calling non-varargs functions.
如果您正在调用printf
使用不同调用约定的函数(因为参数数量可变),这将特别有用。调用这些函数可能与调用非可变参数函数完全不同。
回答by asveikau
After this:
在这之后:
push printtext
call printf
You want:
你要:
addl , %esp
Further explanation:
进一步解释:
Because you're using x86 Linux I assume the calling convention requires the callee to cleanup the parameters. Because you pushed a pointer before calling printf
, your stack is off by 4 after that function's ret
instruction happened.
因为您使用的是 x86 Linux,所以我假设调用约定要求被调用者清理参数。因为您在调用 之前推送了一个指针printf
,所以在该函数的ret
指令发生后,您的堆栈将关闭 4 。
Update:
更新:
Yeah, OK, I was used to Intel syntax so I was getting the order of the arguments backward in my head. Actually the lack of the addl
back to esp
doesn't matter, because you're restoring esp
correctly near your ret
. My next guess is that the string you're passing to printf
is lacking a null terminator... Let me see what gas
does...
是的,好的,我已经习惯了英特尔的语法,所以我在脑海中倒退了参数的顺序。其实缺乏的addl
回esp
无所谓,因为你恢复esp
正常的附近ret
。我的下一个猜测是您传递给的字符串printf
缺少空终止符...让我看看是什么gas
...
Update 2:
更新 2:
OK, gas
null terminates strings for you, so I guess my second hunch was wrong. It looks like you found the issue so the point is moot.
好的,gas
null 为您终止字符串,所以我想我的第二个预感是错误的。看起来你发现了这个问题,所以这一点没有实际意义。
回答by asveikau
the issue was that i was using
问题是我正在使用
pushl printtext
rather that
比较起来
pushl $printtext
Thanks everybody for your help and sorry for wasting your time :P
谢谢大家的帮助,很抱歉浪费你的时间:P