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
我哪里理解错了么? 我应该补充哪面的知识?
1
goodleixiao 2019-06-10 19:38:33 +08:00
你去看看 gdt 内存分配,他的地址是非连续的
|
2
Aruforce OP @goodleixiao 我不是要从 GDT 里面读取数据。。而是用 LGDT 来生成内存分段表...
|
3
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 |
4
lcdtyph 2019-06-10 22:23:13 +08:00 via iPhone
前导空格被吃了…凑合看吧……
|
5
co3site 2019-06-10 22:46:21 +08:00 via Android
细心点,一个字节 8 位,2 个十六进制位,挨个挨个数就不会错了
|
7
Aruforce OP |
8
SakuraKuma 2019-06-11 09:50:19 +08:00
题目的话,重点其实就是,细心点。
esp 的话可以看一下函数调用约定。 |
9
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 |
10
Aruforce OP |
11
Aruforce OP 拼写错误 fix: 16 或者 64 CPU 的时候 是 ESP+2 或者 ESP+8
|
12
lcdtyph 2019-06-11 11:33:08 +08:00 via iPhone
@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 才指向第一个参数。你自己把栈图画出来就明白了 |
13
Aruforce OP |