selph
selph
发布于 2022-03-25 / 304 阅读
0
0

《xchg rax,rax》片段分析0x1d--enter指令

前言

本次是该系列的的第0x1d篇,介绍了据说被各大编译器摒弃的enter指令,这是进入函数时保存栈帧环境的指令


实验环境:

  • Windows10 + VS2022 + masm

0x1d

代码片段链接:xorpd | xchg rax,rax 0x1d

mov      rsp,buff2 + n*8 + 8
mov      rbp,buff1 + n*8
enter    0,n+1

代码分析

enter指令介绍

这里理解的难点在于enter指令:

介绍:enter指令是为了支持高级语言中的变量作用于而加入的,它不是一个伪指令,但是却由于效率原因被各大编译器所摒弃,取而代之的是用多条指令去模拟来提升效率

enter指令格式:enter reservedVarSize, level

  • reservedVarSize:局部变量占用内存大小
  • level:嵌套级别

当level = 0时,相当于:

push ebp 
mov ebp, esp 
add esp, -x

当level != 0 时,例如:enter 10, 3相当于:

push ebp		;保存上一级的ebp
mov ebp, esp	;保存上一级的esp
sub esp, (3-1)*4;用来保存可访问的栈帧的指针,能访问几层就有几个
push ebp		;保存当前栈帧
sub esp, 10		;用于保存局部变量

根据参考资料[2]里所述:这里的嵌套级别的意思是,函数嵌套调用会产生多个栈帧,这里把多个栈帧都保存起来,以便访问其他栈帧里的变量【不是很理解,但从直观上看,这里嵌套级别决定了这里的rsp和rbp中间会多留几个空间】

代码分析

测试代码:

.data
	buff1 db "AAAAAAAA",0
	buff2 db "BBBBBBBB",0
	n equ 0

.code
main proc

	lea      rsp, qword ptr [buff2 + n*8 + 8]
	; 加载buff2 + n*8 + 8的地址到rsp

	lea      rbp, qword ptr [buff1 + 8]
	; 加载buff1 + 8的地址到rbp

	enter    0,   n+1
	;push rbp
	;mov rbp, rsp
	;sub rsp, ((n+1) -1)*8+8	;n*8+8
	;push rbp
	;sub esp, 0

	ret

main ENDP
END

这里使用lea代替mov,在Windows上,这里要获取地址还是得用lea才行,也可能是我哪里没写对

当给n赋值为0的时候:

image-20220326122557794

当给n赋值为1的时候:

image-20220326122638529

这里显示了enter嵌套层级对栈帧范围的影响

参考资料


评论