X86汇编PUSH与POP操作对于变量在内存中高低地址的转换分析

一、高低地址的核心概念

内存可以看作是一段线性的、按字节编号的存储空间,就像一条无限长的街道,每个字节都是一个"房子",每个房子有唯一的"门牌号"(地址):

  • 低地址 :地址数值的内存位置(比如 0x00001000)。
  • 高地址 :地址数值的内存位置(比如 0x00002000)。

举个通俗例子:把内存地址想象成楼层号,低地址是1楼、2楼(数值小),高地址是10楼、20楼(数值大)。

关键特性(x86架构,逆向最常用):

栈的生长方向是从高地址向低地址扩展 ------压栈(push)数据时,栈顶寄存器esp的数值会减小 (指向更低的地址);出栈(pop)数据时,esp数值会增大(指向更高的地址)。

二、结合栈帧的具体地址数值举例

以32位x86系统(逆向最经典场景)为例,用main函数调用add(a=1, b=2)的过程,一步步展示栈地址的变化,所有地址均为十六进制(逆向标准表示)。

前提约定:
  • 32位系统中,每个栈操作(push/pop)占用4字节(地址增减步长为4)。
  • 调用约定为cdecl(C语言默认):参数从右到左入栈,返回地址由call指令保存。
  • 初始状态:main函数的栈帧基址ebp=0x0012FF80(栈帧底部,高地址),esp=0x0012FF80(栈顶,初始与底部重合)。
步骤1:参数入栈(main调用add前)

cdecl约定下,参数从右到左压栈(先压b,再压a):

  1. 压入参数b=2:
    • 执行push 2esp = 0x0012FF80 - 4 = 0x0012FF7C(地址减小,指向更低地址)。
    • 内存地址0x0012FF7C(高地址)存储数值2。
  2. 压入参数a=1:
    • 执行push 1esp = 0x0012FF7C - 4 = 0x0012FF78
    • 内存地址0x0012FF78(低地址)存储数值1。

此时栈地址分布(高→低):

地址(十六进制) 存储内容 说明
0x0012FF7C 2(参数b) 高地址
0x0012FF78 1(参数a) 低地址(栈顶当前)
步骤2:保存返回地址(call指令)

执行call add时,CPU会先把main函数下一条指令的地址(返回地址,假设为0x00401020)压入栈,再跳转到add函数:

  • esp = 0x0012FF78 - 4 = 0x0012FF74
  • 内存地址0x0012FF74存储返回地址0x00401020
步骤3:建立add函数的栈帧

进入add函数后,首先执行栈帧初始化指令:

  1. 保存旧ebp(main的ebp):
    • 执行push ebpesp = 0x0012FF74 - 4 = 0x0012FF70
    • 内存地址0x0012FF70存储0x0012FF80(main的ebp值)。
  2. 设置新ebp(add的栈帧底部):
    • 执行mov ebp, esp,此时ebp = 0x0012FF70(add栈帧的底部,高地址)。
  3. 分配局部变量(比如add的局部变量c):
    • 执行sub esp, 4(分配4字节),esp = 0x0012FF70 - 4 = 0x0012FF6C(add栈帧的顶部,低地址)。
    • 内存地址0x0012FF6C存储局部变量c(初始值随机,比如0)。
最终add栈帧的完整地址分布(高→低)
地址(十六进制) 存储内容 角色 地址属性
0x0012FF70 0x0012FF80(main的ebp) add栈帧底部(ebp) 高地址
0x0012FF74 0x00401020(返回地址) 返回地址 -
0x0012FF78 1(参数a) 函数参数 -
0x0012FF7C 2(参数b) 函数参数 -
0x0012FF6C 0(局部变量c) add栈帧顶部(esp) 低地址

三、补充说明

  1. 上述地址是示例值 ,实际系统中地址会因操作系统(Windows/Linux)、编译器(MSVC/GCC)、ASLR(地址随机化)等因素变化,但高低地址的相对关系永远不变
  2. 64位系统的栈操作逻辑与32位一致,仅地址宽度变为64位(比如0x000000000012FF80),每次push/pop的步长为8字节。
  3. ebp(栈帧基址)的核心作用是"锚定"栈帧:通过ebp+偏移量可以精准访问参数(如ebp+8是参数a)、局部变量(如ebp-4是局部变量c),这是逆向中定位参数/变量的关键。

总结

  1. 内存地址数值越大,地址越高;数值越小,地址越低,栈在x86架构下从高地址向低地址生长。
  2. 栈帧中ebp指向栈帧底部(高地址),esp指向栈帧顶部(低地址),push操作使esp减小,pop使esp增大。
  3. 函数调用时,栈地址从高到低依次存储:旧ebp → 返回地址 → 函数参数 → 局部变量。
相关推荐
我在人间贩卖青春9 天前
汇编之伪指令
汇编·伪指令
我在人间贩卖青春9 天前
汇编之伪操作
汇编·伪操作
济6179 天前
FreeRTOS基础--堆栈概念与汇编指令实战解析
汇编·嵌入式·freertos
myloveasuka9 天前
汇编TEST指令
汇编
我在人间贩卖青春9 天前
汇编编程驱动LED
汇编·点亮led
我在人间贩卖青春9 天前
汇编和C编程相互调用
汇编·混合编程
myloveasuka10 天前
寻址方式笔记
汇编·笔记·计算机组成原理
请输入蚊子10 天前
《操作系统真象还原》 第六章 完善内核
linux·汇编·操作系统·bochs·操作系统真像还原
myloveasuka10 天前
指令格式举例
汇编·笔记·计算机组成原理
我在人间贩卖青春11 天前
汇编之分支跳转指令
汇编·arm·分支跳转