我是汇编语言的新手。我有以下汇编代码:
.intel_syntax noprefix
.bits 32
.global asm0
asm0:
push ebp
mov ebp,esp
mov eax,DWORD PTR [ebp+0x8]
mov ebx,DWORD PTR [ebp+0xc]
mov eax,ebx
mov esp,ebp
pop ebp
ret
我想弄清楚以下命令返回什么: asm0(0x2a,0x4f)。
我正在运行Ubuntu,并且已经下载了NASM。我一直在这里阅读汇编代码的语法:https://www.tutorialspoint.com/assembly_programming/assembly_basic_syntax.htm,但仍无法弄清楚。我已经用C ++编写了三年代码,但这仍然让我感到困惑。任何有更多经验的人都可以帮助我解决这个问题吗?
编辑:上面的代码说了推入和移动,因此它看起来像堆栈数据结构吗?然后它在最后返回。但是,此函数没有参数。怎么办?
运行gcc -m32 -g main.c程序集时出现错误消息。
myName@myName:~/Downloads$ gcc -m32 -g main.c file.S
main.c: In function ‘main’:
main.c:5:17: warning: implicit declaration of function ‘asm0’ [-Wimplicit-
function-declaration]
printf("%d", asm0(123,456));
^~~~
file.S: Assembler messages:
file.S:2: Error: unknown pseudo-op: `.bits'
答案 0 :(得分:1)
您的函数在堆栈中返回地址上方查找其2个args。在设置了传统的堆栈框架之后,请注意对[ebp+8]
和[ebp+12]
的访问。
您不会在asm中声明args;这是一个高级概念,您可以自己在asm的代码中实现。
push
在调用堆栈上运行,而不是完全在堆栈数据结构上运行。
https://felixcloutier.com/x86/PUSH.html。它只是减少了ESP并存储到[esp]
。这样做是为了保存/恢复调用者的EBP,这是制作传统堆栈框架的一部分。这是非常基础的内容,如果您还没看过,请阅读更多教程或指南。
您可以轻松地尝试代码,并通过C程序调用它来查找代码。
除非您不能,因为您的asm无法组装。 .bits 32
不是有效的GAS指令,但是显然,这显然是GNU汇编程序(GAS)语法。除了GAS本身和clang的内置汇编程序外,我没有其他具有.intel_syntax noprefix
指令的汇编程序,而且它们都不支持.bits 32
。因此,我猜想此功能来自教程或其他内容,并且是通过NASM语法(bits 32
)或其他内容手动移植到GAS的,未经实际测试。
但是您不需要也不应使用该指令或与GAS等效的.code32
。汇编成32位目标文件时,默认值是32位代码,因此,如果您只使用.code32
而不使用{,则gcc foo.s
将允许您将32位代码汇编成64位目标文件。 {1}},然后您将遇到难以调试的问题,那就是运行时,而不是汇编时出现的明显错误。
因此,请删除-m32
行,以解决问题中的错误消息。
要摆脱警告消息,请提供适当的标题和原型,以扩展我在评论中写的单行代码。
.bits 32
该函数也是有问题的:它掩盖#include <stdio.h>
int asm0(int,int);
int main(){
printf("%d\n", asm0(123,456));
}
,这是i386 System V调用约定中的一个保留调用的寄存器。 (就像所有普通的x86调用约定一样。)
gcc使得依赖于EBX的代码被保留并实际上崩溃了。 (不过,您仍然可以使用调试器进行单步调试,因为崩溃发生在ebx
返回之后。)
但是您可以制作一个可执行的可执行文件,让您只运行它即可查看返回的arg:
asm0
peter@volta:/tmp$ gcc -g -Og -no-pie -fno-pie -m32 main.c asm0.s
peter@volta:/tmp$ ./a.out
456
返回其第二个arg(通过将其复制到返回值寄存器EAX)。它将其加载到EBX,然后将EBX复制到EAX,覆盖第一个arg的加载结果。
您可以通过asm0
gdb ./a.out
GDB突出显示了在每个步骤中更改了哪些寄存器。
有关更多调试提示,请参见https://stackoverflow.com/tags/x86/info的底部。
进一步阅读: