问个汇编的问题?原谅我半路出家

2019-06-10 18:55:38 +08:00
 Aruforce

32 bit

_load_gdtr:		; void load_gdtr(int limit, int addr);
	MOV		AX,[ESP+4]		; limit,
	MOV		[ESP+6], AX		;
	LGDT	[ESP+6]
	RET

load_gdtr ( 0xffff,0x00270000 )

压栈后 字节序:FFFF 0000 0000 2700

经过 两次 MOV 操作后 字节序是 FFFF 00FF FF00 2700 ?

但是 别人告诉我是 FFFF FFFF 0000 2700

我哪里理解错了么? 我应该补充哪面的知识?

2445 次点击
所在节点    程序员
16 条回复
goodleixiao
2019-06-10 19:38:33 +08:00
你去看看 gdt 内存分配,他的地址是非连续的
Aruforce
2019-06-10 22:00:30 +08:00
@goodleixiao 我不是要从 GDT 里面读取数据。。而是用 LGDT 来生成内存分段表...
lcdtyph
2019-06-10 22:19:56 +08:00
假设是小端机器

进入函数之后 ESP 指向返回地址,从 ESP+4 开始栈上数据分布如下:
+4 +5 +6
ESP+4: FF FF 00 00 00 00 27 00
ESP+C: .........

MOV AX, [ESP+4] 之后 AX=FFFF
MOV [ESP+6], AX 之后即是从上面 ESP+6 开始写入 16bit 数据,结果就是
+4 +5 +6
ESP+4: FF FF FF FF 00 00 27 00
lcdtyph
2019-06-10 22:23:13 +08:00
前导空格被吃了…凑合看吧……
co3site
2019-06-10 22:46:21 +08:00
细心点,一个字节 8 位,2 个十六进制位,挨个挨个数就不会错了
Aruforce
2019-06-11 09:30:11 +08:00
@lcdtyph 你好,请问能个给个图片么? 我还是没看明白 ESP 到底开始指向了哪里? 谢谢
Aruforce
2019-06-11 09:38:46 +08:00
SakuraKuma
2019-06-11 09:50:19 +08:00
题目的话,重点其实就是,细心点。

esp 的话可以看一下函数调用约定。
x1314aq
2019-06-11 10:38:48 +08:00
@Aruforce esp 最开始指向 caller 的返回地址;这是 x86 的函数调用约定,函数参数从右往左依次入栈,如果是用 call 指令进行调用的话,还会把返回地址入栈;因此当_load_gdtr()开始执行的时候,栈是这样一个排布:
(小端序)
+0 +4 +5 +6 +7
ret_addr 0xff 0xff 0x00 0x00 0x00 0x00 0x27 0x00
^
|
esp
Aruforce
2019-06-11 11:00:09 +08:00
我大概明白了...在函数入栈的时候
```asm
push ebp ;32 位 CPU...占用 4 个字节
mov ebp,esp ; ebp 存储 调用方的栈顶
...
mov esp, ebp ;恢复调用方栈顶
pop ebp ;从 stack 顶端 读取 4 个 byte 到 EBP,也就是调用方的元 EBP
ret

```

也就是说 ESP+4 只是跳过了调用方的 EBP 的值,而如果是 16 或者 32 的 CPU 的话就是 ESP+2 或者 ESP+8 了对么?

@lcdtyph @x1314aq
Aruforce
2019-06-11 11:01:24 +08:00
拼写错误 fix: 16 或者 64 CPU 的时候 是 ESP+2 或者 ESP+8
lcdtyph
2019-06-11 11:33:08 +08:00
@Aruforce
你可能还是没太明白,在题目里这个例子里没有 ebp 的事情。这个函数太简单了甚至都没有开辟栈帧。

1. esp 永远指向栈顶的第一个元素
2. 指令 call _load_gdtr 可以理解成两步:先 push eip,再 jmp _load_gdtr。push eip 之后栈顶就是返回地址了
3. 进入函数后 esp+4 是为了跳过返回地址。

如果开辟了栈帧那么有两种本地变量的寻址方式,分别是 esp 寻址和 ebp 寻址。其中比较简单的就是 ebp 寻址,在你 10 层的回复中 push ebp; mov ebp,esp 之后 ebp 指向栈上的那个旧的 ebp,此时 ebp+4 指向返回地址,esp+8 才指向第一个参数。你自己把栈图画出来就明白了
Aruforce
2019-06-11 14:35:25 +08:00
@lcdtyph

! [1] ( https://imgur.com/WJWbglI)

你好这样理解 正确么?
lcdtyph
2019-06-11 14:58:31 +08:00
@Aruforce #13
栈里数据的图是对的,但是“ call 指令”那里的操作不太对
1. 函数参数的压栈不是“ call 指令”来做的,需要 caller 自己做。
2. EIP 入栈之后还有一步跳转操作,根据不同类型的 call 会有不同的动作,不过结果都是使 EIP 指向函数的入口
3. push ebp 以及之后的操作都不是“ call 指令”的行为,是 callee 自己的行为
Aruforce
2019-06-11 15:14:04 +08:00
@lcdtyph 意思是 CALL 只是执行了 修改 EIP,EIP 入栈,还有 JMP 这一组操作?
lcdtyph
2019-06-11 16:11:09 +08:00

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/572569

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX