as汇编链接libc时 AT&T汇编如何获取栈帧局部变量地址传入scanf
问题本质
你之前的两种尝试都不符合32位x86 GAS的寻址规则,无法传递局部变量的地址:
- 执行
pushl -4(%ebp)时,CPU会按照内存间接寻址规则,读取ebp - 4位置存储的4字节数值压栈,本质是传递变量x本身的值,而非它的地址。 - 执行
pushl $-4(%ebp)时,$前缀代表立即数寻址,要求操作数是汇编阶段可确定的固定值,直接嵌套内存操作数属于语法错误,汇编器要么直接报错,要么生成完全错误的数值,根本无法计算运行时的栈帧地址。
正确实现方案
GAS汇编没有直接压入内存有效地址的指令支持,需要借助leal(加载有效地址)指令完成取址:该指令专门用于计算内存操作数的有效地址,将计算结果直接写入目标寄存器,全程不会读取对应内存的存储值,和C语言&x的语义完全等价。
替换后的scanf调用代码如下:
# 计算 -4(%ebp) 对应的实际内存地址(即局部变量x的地址),存入eax寄存器 leal -4(%ebp), %eax # 压入x的地址,作为scanf接收输入的目标参数 pushl %eax # 压入格式字符串地址,作为scanf的第一个参数 pushl $msg_template call scanf
补充说明
上述逻辑和C语言编译器生成的原生汇编完全一致:局部变量x的实际运行时地址为ebp寄存器值 - 4,leal会在CPU运行时完成这个地址算术计算,不会触碰该地址存储的变量值,完全满足scanf对指针参数的要求。
内容的提问来源于stack exchange,提问作者gogomapmo87
相关产品推荐
相关产品推荐

