4

Consider the following procedure that fills a dword array with values, and takes in 2 parameters: at EBP + 08h is the size of the array, and at EBP + 0Ch is the offset of the given array. (i.e. 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

Where I try to move EDI into [ESI + 04h * [EBP - 04h]] is an example of what I am trying to do, since the dword at address EBP - 4 is the index of the array.
Is there any way to actually move EDI into the dword at address ESI + 4 * the dword at address EBP - 4? Or am I looking at this the wrong way?

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
mike bayko
  • 375
  • 5
  • 20

3 Answers3

4

You're making this procedure overly complicated. All you need to do is the following:

 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

Most ABI's consider EAX, ECX & EDX volatile, but if you need to preserve them, by all means.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Shift_Left
  • 1,208
  • 8
  • 17
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.

The value at [EBP-4] will hold an incrementing index in your dword array. I see 2 solutions to this little problem:

  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
    

An error to consider:

INC EBX

This inc will give you 1 iteration too many!


Given that you want to fill the array with increasing values that are precisely 1 greater than the index of the element (a[0]=1, a[1]=2, a[2]=3,...) you can write a much better routine by pre-incrementing the index and compensating for this action through subtracting 4 from the address:

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

Less registers used also means less registers to preserve!

Fifoernik
  • 9,779
  • 1
  • 21
  • 27
  • "variables" are a high level concept. You can still consider your loop-counter a variable if you keep it in a register and don't need any stack space to spill it. – Peter Cordes Jul 27 '17 at 05:00
2

It requires two instructions:

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

You'll also might consider saving/restoring EAX in the preamble and epilogue of the function. In most environments, EAX does not need to be preserved.

wallyk
  • 56,922
  • 16
  • 83
  • 148
  • I could be wrong, but I think the term you're looking for is "function epilogue." :) – David Hoelzer Jul 20 '17 at 01:10
  • 1
    @DavidHoelzer: Yep, that's what happens when I go hiking for hours and come back and immediately try to write a coherent answer. Thanks. – wallyk Jul 20 '17 at 04:47
  • 3
    I can't try right now, but are you sure that `[ESI + 4*[EAX]]` shouldn't be `[ESI + 4*EAX]` ? And the terms are prologue and epilogue. – Rudy Velthuis Jul 20 '17 at 08:17
  • FWIW, in which ABI must EAX be preserved? Since this is about MASM, I assume it is for Windows, and I don't know any Windows calling convention where EAX must be saved. – Rudy Velthuis Jul 20 '17 at 08:20
  • No x86 calling convention requires preserving EAX. You only need to save it if there's a value in it that *you* want. And yes, the terms are "prologue" and "epilogue". – Cody Gray - on strike Jul 20 '17 at 09:22
  • 1
    `[ESI + 4 * [EAX]]` is not legal Intel syntax. `[ESI + 4 * EAX]` would be ok in 32 and 64 protected mode of x86. – Ped7g Jul 20 '17 at 09:40
  • @Ped7g: I have fixed it. Thanks! – wallyk Jul 20 '17 at 21:52
  • @RudyVelthuis: Thanks for pointing that out. I didn't look way up to the question; I was dealing with the instruction substitution in isolation. – wallyk Jul 20 '17 at 21:53