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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 02:27:49  来源:igfitidea点击:

calling assembly functions from c

clinuxassemblygas

提问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 printtextto push $printtext.

更改push printtextpush $printtext

As it is, you're loading a value from the address printtextand pushing that, rather than pushing the address. Thus, you're passing 'test'as a 32-bit number, rather than a pointer, and printfis 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 (-Son 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 printfwhich 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 retinstruction 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 addlback to espdoesn't matter, because you're restoring espcorrectly near your ret. My next guess is that the string you're passing to printfis lacking a null terminator... Let me see what gasdoes...

是的,好的,我已经习惯了英特尔的语法,所以我在脑海中倒退了参数的顺序。其实缺乏的addlesp无所谓,因为你恢复esp正常的附近ret。我的下一个猜测是您传递给的字符串printf缺少空终止符...让我看看是什么gas...

Update 2:

更新 2:

OK, gasnull terminates strings for you, so I guess my second hunch was wrong. It looks like you found the issue so the point is moot.

好的,gasnull 为您终止字符串,所以我想我的第二个预感是错误的。看起来你发现了这个问题,所以这一点没有实际意义。

回答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