以下是一个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]
而且,为什么我们需要在此处进行类型转换?
我还需要该程序的内存布局以了解堆栈机制。我在互联网上发现了很多图片,但是我不确定哪一个可以代表该程序。
答案 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 。