为什么我们不能使用esp寄存器直接引用内存地址?

时间:2019-04-04 21:05:59

标签: linux assembly x86 nasm

以下是一个x86汇编程序,该程序由NASM在64位CentOS上通过远程终端进行汇编,与C程序一起使用时,它绝对可以正常工作。

section .data
section .text
        global  strlen

strlen:
        push    ebp
        mov     ebp, esp                ; obtain the address of the
        mov     eax, DWORD [ebp+8]      ; address of string to eax

        xor     ecx, ecx                ; initialize counter to zero

count_loop:
        mov     bl, [eax]               ; obtain the address of the 1st character
        cmp     bl, 0                   ; check the null value
        je      length_exit             ; exit if the null-character is reached
        inc     ecx                     ; increment counter
        inc     eax                     ; increment the address
        jmp     count_loop              ; start the loop again

length_exit:
        mov     eax, ecx                ; return ecx
        pop     ebp                     ;
        ret

首先,它是32位还是64位程序?如果它是32位程序,为什么在函数名中没有下划线字符(_)?

我知道以下代码段正在创建堆栈框架:

push    ebp
mov     ebp, esp                ; obtain the address of the
mov     eax, DWORD [ebp+8]      ; address of string to eax

但是,为什么我们需要保存 ebp?我们为什么不能只写以下内容? :

 move eax, DWORD [esp+8]

而且,为什么我们需要在此处进行类型转换?

我还需要该程序的内存布局以了解堆栈机制。我在互联网上发现了很多图片,但是我不确定哪一个可以代表该程序。

2 个答案:

答案 0 :(得分:1)

  

如果它是32位程序,为什么在函数名中没有下划线字符(_)?

因为它不是Windows。

Linux / ELF系统在任何模式下均不使用前导_,而与CPU架构无关。

  

为什么我们不能只写以下内容?:move eax, DWORD [esp+8]

可以。 (如果您正确拼写mov。实际上,编译器默认在启用优化后使用-fomit-frame-pointer,因此它们仅将EBP用作具有C99可变长度数组或alloca的函数中的帧指针。

32位和64位模式允许ESP作为寻址模式的基地址,这与16位模式不同,在16位模式中[sp+2] 不可编码的。

但是请记住,如果您没有按ebp,则ESP仍指向返回地址,因此第一个arg将位于[esp+4]

  

而且,为什么我们需要在此处进行类型转换?

您不知道。寄存器操作数表示操作数的大小。

(这不是真正的类型转换,只是操作数大小的说明符。它不会为您做浮点整数转换;您必须为此使用cvtss2si eax, [esp+4]。)

您只需要 一个操作数大小的说明符,用于mem,立即指令,例如cmp dword [esp+4], 0,这在字节/字/双字操作数大小之间是模棱两可的。或对于movzx eax, byte [esp+4]之类的指令,其中寄存器操作数暗指内存操作数的大小。

答案 1 :(得分:0)

原因源自指令的编码方案。
英特尔手册第2.1.5节中的表2.2 显示了可能的组合。

它表明ESP寄存器的(可能)编码用于指示紧随其后的 SIB 字节(指令扩展字节):

  

[-] [-]的名称表示SIB紧随ModR / M字节。

因此,实际上ESP寄存器的编码被重新用于编码一个额外的指令字节,即SIB字节。

SIB 字节中,[ESP]的指令编码也是一个例外。看表2.3