在汇编语言中,是否可以对解除引用的内容再进行解除引用操作?

4
考虑以下填充dword数组的过程,它接受2个参数:在EBP + 08h处是数组的大小,在EBP + 0Ch处是给定数组的偏移量。(例如:OFFSET myarray):
MyProc PROC
PUSH EBP
MOV EBP, ESP
SUB ESP, 04h
PUSH EDI
PUSH ESI
PUSH EBX
MOV EBX, [EBP + 08h] ;move the size of the array into EBX
MOV [EBP - 04h], 00h ;EBP - 04h will be the counter (or the index.)
MOV ESI, [EBP + 0Ch] ;move the offset of the array into ESI
MOV EDI, 01h
INC EBX
@@:


MOV [ESI + 04h * [EBP - 04h]], EDI ;How can I actually move EDI into
;the dword found at address ESI + 4 * the value found at address EBP - 4?


INC [EBP - 04h] ;increment the counter and the value to be stored.
INC EDI
CMP [EBP - 04h], EBX
JNE @B
POP EBX
POP ESI
POP EDI
MOV ESP, EBP
POP EBP
RET
MyProc ENDP

我试图将EDI移动到[ESI + 04h * [EBP - 04h]]中,这是我尝试做的一个示例,因为地址EBP - 4处的双字是数组的索引。
是否有任何方法可以将EDI实际移动到地址ESI + 4 * 地址 EBP - 4处的双字中?还是我的想法有误?

3个回答

4

您正在使这个过程过于复杂化。您只需要按照以下步骤操作:

 push  ebp
 mov   ebp, esp

 xor   eax, eax            ; Fill buffer with nulls
 mov   ecx, [ebp+8]        ; Number of dwords to fill
 push  edi
 mov   edi, [ebp+12]
 rep   stosd
 pop   edi

 leave
 ret   8                    ; Pop arguments passed by caller

大多数ABI认为EAX、ECX和EDX是易变的,但如果您需要保留它们,那就请保留。

3
MOV [ESI + 04h * [EBP - 04h]], EDI ;How can I actually move EDI into
       ;the dword found at address ESI + 4 * the value found at address EBP - 4?
INC [EBP - 04h] ;increment the counter and the value to be stored.

[EBP-4]中的值将保存在您的dword数组中的递增索引。我看到这个小问题有两个解决方案:

  1. You keep using a local variable and write the problematic instruction in 2 steps:

    mov eax, [ebp-4]
    mov [esi+eax*4], edi
    inc [ebp-4]
    
  2. You don't use the local variable at all, and keep the index in a register:

    mov [esi+eax*4], edi
    inc eax
    
考虑的错误:

注:

INC EBX

这个inc会使循环多执行一次!


如果你想要用递增的值来填充数组,这些值恰好比元素的索引大1(a[0]=1, a[1]=2, a[2]=3,...),你可以通过预先增加索引并通过从地址中减去4来进行补偿,编写一个更好的程序:

MyProc PROC
PUSH EBP
MOV  EBP, ESP
PUSH ESI

xor  eax, eax         ;EAX will be the counter (or the index.)
mov  esi, [ebp + 12]  ;move the offset of the array into ESI
@@:
inc  eax              ;increment the counter and the value to be stored.
mov  [esi + eax * 4 - 4], eax
cmp  eax, [ebp + 8]   ;Compare index to size of the array
jb   @B

POP ESI
MOV ESP, EBP
POP EBP
RET
MyProc ENDP

使用更少的寄存器意味着需要保留的寄存器也会更少!


“变量”是一个高级概念。如果您将循环计数器保留在寄存器中并且不需要任何堆栈空间来溢出它,则仍然可以将其视为变量。 - Peter Cordes

2

需要两个指令:

MOV    EAX, [EBP - 04h]
MOV   [ESI + 4*EAX], EDI

在函数的开头和结尾,您可能还需要考虑保存/恢复EAX。在大多数环境中,不需要保留EAX。


我可能错了,但我认为你要找的术语是“函数结尾语”。 :) - David Hoelzer
1
@DavidHoelzer:没错,当我徒步行走数小时后回来并立即尝试写出连贯的答案时就会发生这种情况。谢谢。 - wallyk
3
我现在无法尝试,但你确定[ESI + 4*[EAX]]不应该是[ESI + 4*EAX]吗?这里的术语是序言和尾声。<g> - Rudy Velthuis
值得一提的是,在哪种ABI中必须保存EAX?由于这是关于MASM的,我认为它是为Windows设计的,并且我不知道任何必须保存EAX的Windows调用约定。 - Rudy Velthuis
1
"[ESI + 4 * [EAX]]" 不是合法的英特尔语法。在x86的32位和64位保护模式中,"[ESI + 4 * EAX]" 是可以的。 - Ped7g
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接