- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我最近开始使用 MASM 语言学习 x86 汇编。
我正在使用 Isreal Gbati 的 Udemy 类(class)“x86 Assembly Language From Ground Up”来学习。
下面的代码来自类(class)中的一课,(这不是我想出的代码)。该函数由 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,因为它在声明中告诉我们这一点。
所有这些都可能在类(class)的后面解释,我相信我的问题的答案很简单。但是,我正在尝试慢慢来以确保我了解自己在做什么。是的,我知道 Assembly 不是 C,所以像我这样比较这两种语言可能不是正确的方法,但我正在学习 Assembly 以更好地理解 C 中的内存管理内容。
谢谢大家的宝贵时间!
最佳答案
When we use
pop
, from what I understand is kind of like usingfree()
in C.
事实并非如此。 push x
将 x
复制到栈顶,并移动栈指针,使新的栈顶低于压入的值(记住在 x86 上,栈向下增长在内存中)。 pop x
做相反的事情:将堆栈的顶部复制到 x
中,然后移动堆栈指针,使新的顶部位于弹出值之上(即值是从堆栈中删除)。
实际上,伪 C 等效项是这样的:
void push(int x) {
--esp;
*esp = x;
}
void pop(int *x) {
*x = *esp;
++esp;
}
因此,pop ebp
并不是“清理ebp
寄存器”的意思,而是“从栈中弹出一个值,存入ebp中”
注册。”由于我们之前推送了 ebp
,这只是将其还原为结束我们函数的一部分。
Also, I understand that
ret
is used at the end of the procedure, but how do we know that this function is returning a value at all?
您可以说在汇编程序世界中,每个函数都返回一个值。调用约定指定如何返回值。在 x86 上,返回值存储在 eax
寄存器中。所以 ret
跳转到调用函数的地方,此时 eax
中的任何内容都是调用者获得的返回值。这就是该函数在 eax
中计算总和的原因,因此它就在调用者期望的位置。
同样,在伪 C 中,您可以想象一个普通的 C return
语句是这样实现的:
void return(int x) {
eax = x;
ret;
}
关于c - 如何在 MASM 中使用 pop 和 ret,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57089912/
有什么区别: 1) !ret 2) ret != 0 ? if (ret != 0 || stack[fd] == NULL || stack[fd][0] == '\0') { if (!ret
我正在使用 java 客户端 (jrets) 来查询 RETS 服务器。此 rets 服务器不支持 OFFSET 功能。 服务器管理员告诉我使用 MODIFIED 字段作为翻阅记录的一种方式。但是,我
我想从 RETS 服务器下载所有属性(property) list ,包括所有照片 URL。我正在使用 DMQL2 和 PHRETS 库。属性和照片对象存储在 RETS 服务器的不同表中。 要获取所有
各位, 我将使用 RETS 进行真实项目。我有一份文件,说明我的经理实际上在寻找什么。但我真的不知道如何开始使用 RETS MLS,因为它有很多这样的文档。 通过一些研发,我几乎没有想出任何有值(va
我正在尝试在 Microsoft visual studio 2013 on C++ 上编译一个为 linux 编写的程序(是 C 和 C++ 的混合体 (#include .h),我将全部转换为 C
当我尝试像这样编写自己的decay_t时: #include template struct auto_decay { auto operator () () noexcept {
我经常看到通过测试小于零而不是显式定义来检查 POSIX 函数错误的代码,通常唯一的错误代码使用 -1。也就是 ret = function(); if (ret < 0) { ... } 对
考虑以下空 C 程序(标准保证编译器执行隐式 return 0): int main(int argc, char* argv[]) {} 您可以将任何逻辑添加到此函数中来操作 argc 和 argv
我在 ubuntu 12.04 和 auctex 11.86 上运行 emacs 23.3.1。每当我去编译 latex 文档(使用 C-c C-c)时,如果没有错误,一切都编译得很好。但是,如果有任
我有 RETS 元数据文件,我想将其转换为数据库模式,这样我就可以查询我的数据库而不是 RETS 服务器。 有谁知道可以使用 xml 并将其转换为数据库模式的工具?或者可能是数据库模式本身? 一切都包
由于 ret 指令是一个间接调用,x86 上的 ret 指令会停止流水线,还是以某种方式优化为更直接的调用? 最佳答案 根据英特尔优化引用手册,分支预测单元包含一个 Return Stack Buff
我有以下头文件: #include #include #include #include #include #include /** **/ // size: 1B typedef en
我目前正在开发一个网站并从 RETS(房地产交易标准)API 中提取列表。我的一切工作正常,但我的问题是在尝试深入挖掘查询时出现的。作为引用,我正在使用 Node RETS Client但我不确定它与
if(isset($_POST['update'])) { $rets_login_url = $Fetch['rets_url']; $rets_username = $Fetch['rets_us
我有这个函数,它主要由内联汇编码成。 long *toarrayl(int members, ...){ __asm{ push esp mov eax, me
int suma(int* array, int len) { asm(" xor %eax, %eax # resultado = 0 \n"
我对汇编很陌生,我不明白在 proc 结束时你用 ret 写一个数字的确切含义是什么。陈述。 像这样: Function Proc push ax cx . ...body... . pop cx a
我正在尝试使用 PHRETS 从 rets 服务器在 WordPress 中添加帖子。不幸的是,正在添加重复的帖子。我已使用 WP 查询使用元键和值检查现有帖子。当我尝试添加 10 或 50 个帖子时
我有以下程序: SECTION .text main: mov ebx, 10 mov ecx, 50 repeat: inc ebx loop repeat
假设我正在 x86 汇编中编写一个例程,例如“add”,它将两个作为参数传递的数字相加。 在大多数情况下,这是一个非常简单的方法: push ebp mov ebp, esp mov eax, [eb
我是一名优秀的程序员,十分优秀!