汇编过程

汇编系列文章:
https://www.jianshu.com/nb/29822876

stack的使用

  • 使用SS和ESP进行寻址,每一次push和pop都是对栈顶操作,栈顶在低地址,同时是指向顶部存储的内容。如PUSH后,会先移动后再push进去东西。
  • PUSH、POP都是只有一个操作数,因为只有一个栈。
  • 注意由于后进先出,PUSH和POP的操作对象顺序相反。
  • PUSHFD、POPFD:用于EFLAGS寄存器
  • PUSHAD、POPAD:所有32位通用寄存器,顺序:EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI
  • PUSHA、POPA用于16位

过程procedure定义:

  • 输入输出可以使用寄存器
  • 使用PROC和ENDP定义,里面使用ret,直接用call调用
  • ret用来进行EIP赋值,继续执行调用前的下一条的指令
  • USES操作符:在PROC之后加上USES esi ecx可以让编译器自动在PROC内部加上两个寄存器的push和pop操作
  • 用机器码编译出来的procedures
  • 自己生成lib时需要先把每一个asm编译成obj然后把他们添加在lib文件中
  • 使用include来声明函数原型

64位

  • 用PROTO,使用的栈指针是RSP,每次减8;
  • 前四个参数必须放在RCX、RDX、R8、R9里
  • 必须在stack中预留至少32bytes,子过程调用时栈指针在16-byte边界上对齐

Stack Frames栈帧

  • 也叫做activation record,用于记录调用过程传递的参数、返回地址、保存的寄存器及局部变量的值
  • 调用的时候参数入栈,调用过程,被调用的过程将EBP推入栈中,在函数调用时把原来的栈顶esp变成被调用函数的栈底ebp。如果需要局部变量,会在esp上减小常数以存放。
    • 子过程中,push ebpmov ebp, esp,最后pop ebp
  • stack parameters:比用寄存器传递参数更方便,直接把参数倒序入栈。
    • 值传递时,为了保证栈对齐,保护模式中只使用32位值作为参数,返回值放在EAX里面,如果被调用过程没有把参数清除就自己清除这个栈。
    • 引用传递时,传递offset
  • 栈传参数&清除
    • 在call之前push,如push两个参数,在子过程中可以使用[esp + 8]、[esp + 12]获取参数
    • 最后可以由子过程ret 8来清除参数(相当于让esp移动),或者在caller中进行(让esp移动)
  • 局部变量
    • 如函数中,int x = 10,就在改变ebp、esp之后sub esp 4,并且把局部变量存进去。
    • 高到低:参数、return地址、ebp、局部变量
  • ENTER:为被调用过程保留栈帧(push ebpmov ebp espsub esp, n
  • LEAVE:mov esp ebppop ebp
  • LOCAL伪指令:local var1:BYTE, var2:DWORD这样声明
  • LEA:获取栈帧中内容或者局部变量的offset,而OFFSET只能获取常offsets

INVOKE

  • INVOKE后跟PROC、参数列表
  • 64位不可用

PROC

  • label PROC [attributes] [USES list], params

PROTO

  • label PROTO paramslist

参数类型

  • 输入参数、输出参数、输入输出参数