我最近开始使用MASM语言学习x86 Assembly。
我正在使用Isreal Gbati的Udemy课程“从头开始的x86汇编语言”来学习。
以下代码摘自该课程中的一课(不是我想出的代码)。此函数在C程序中由main调用。在这里:
#include <stdio.h>
#include <stdlib.h>
extern int AdderASM(int a, int b, int c);
int main(void)
{
int a = 17;
int b = 11;
int c = 14;
int sum = AdderASM(a, b, c);
printf("A = %d\n", a);
printf("B = %d\n", b);
printf("C = %d\n", c);
printf("SUM FROM ASSEMBLY FUNCTION = %d\n", sum);
return 0;
}
这是程序集:
.386
.model flat, c
.code
AdderASM PROC
PUSH EBP
MOV EBP, ESP
MOV EAX, [EBP+8]
MOV ECX, [EBP+12]
MOV EDX, [EBP+16]
ADD EAX, ECX
ADD EAX, EDX
POP EBP
RET
AdderASM ENDP
END
我不理解以下内容:
当我们使用pop
时,据我所知有点像在C语言中使用free()
。如果我错了,请纠正我
那为什么我们只在EBP寄存器上使用pop?我们不应该同时弹出ECX和EDX寄存器吗?
我知道在C函数中,需要在函数结束之前释放由malloc()
分配的内存的指针。所使用的寄存器都是通用的32位寄存器,但是EBP作为堆栈帧指针有特殊用途。这就是为什么需要释放它的原因?
此外,我知道在该过程的末尾使用了ret
,但是我们怎么知道该函数完全返回一个值?
为了更好地解释我的问题,这是用C语言编写的相同函数:
int AdderClang(int a, int b, int c)
{
return a + b + c;
}
如果我只放置return;
而不是return a + b + c;
,我不知道会发生什么,但这不是预期的结果。我们还可以说这个C函数返回一个int,因为它在声明中告诉了我们。
所有这些都可以在本课程的后面部分进行解释,我敢肯定,对我的问题的回答很简单。但是,我试图慢慢走,以确保我了解自己在做什么。是的,我知道Assembly不是C,因此比较两种语言可能不是正确的方法,但是我正在学习Assembly以更好地理解C中的内存管理知识。
谢谢大家的光临!
答案 0 :(得分:6)
当我们使用
export class GitHub{ constructor(){ this.clientID='6ea9567c0f22d48fb20e'; this.clientSecret='a4ec6e6b2040ddd5d197079014f8a4e0fb7fe839'; this.repos_count=5; this.repos_sort='created: asc'; } async getUser(user){ let response = await fetch(`https://api.github.com/users/${user}?clientID=${this.clientID}&clientSecret=${this.clientSecret}`); let repoResponse = await fetch(`https://api.github.com/users/${user}/repos?per_page=${this.repos_count}&sort=${this.repos_sort}?clientID=${this.clientID}&clientSecret=${this.clientSecret}`); let parsedJson = await response.json(); let reposJson = await repoResponse.json(); return { data:parsedJson, reposJson } } }
时,据我所知有点像在C语言中使用pop
。
事实并非如此。 free()
将push x
复制到堆栈的顶部,并移动堆栈指针,使新的顶部位于所推入的值以下(请记住,在x86上,堆栈在内存中向下增长)。 x
的作用相反:将堆栈的顶部复制到pop x
中,然后移动堆栈指针,使新的顶部位于弹出的值之上(即,从堆栈中删除该值)。 / p>
有效地,伪C等效项是这样:
x
因此,void push(int x) {
--esp;
*esp = x;
}
void pop(int *x) {
*x = *esp;
++esp;
}
并不意味着“清理pop ebp
寄存器”,而是意味着“从堆栈中弹出一个值并将其存储在ebp
寄存器中”。由于我们先前按下过ebp
,因此这只是在结束功能时将其还原。
此外,我知道在该过程的末尾使用了
ebp
,但是我们怎么知道该函数完全返回一个值?
您可以说在汇编世界中,每个函数都返回一个值。调用约定指定如何返回值。在x86上,返回值存储在ret
寄存器中。因此,eax
跳转到调用函数的位置,此时ret
中的内容就是调用者作为返回值得到的。这就是为什么函数在eax
中计算总和的原因,因此恰好在调用者期望的位置。
同样,在伪C中,您可以想象正常的C eax
语句是这样实现的:
return