2

I'm trying to sent DWORD variable into function as pointer paramater

variable1 dd 1
...
push [variable1]  ; push variable adress
call _InitPoiner
...
_InitPoiner:
    ;
    push ebp
    mov ebp, esp
    ;
    lea eax, [ebp+8]       ; load address
    mov dword [eax], 10    ; move value 10 into that address

    pop ebp
    ret
...
push [variable1]
push sdigit ; where sdigit db '%d', 0x0D, 0x0A, 0
call [printf]

but variable1 is 1, not 11 , why?

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Alatriste
  • 527
  • 2
  • 6
  • 21
  • Making sure that you pop your vars when done yes? Looking at your example, I see no way that the variable could ever be 11. It starts as 1 at the `dd` assignment, then if your math in the `lea` is correct, it would then be 10. If you were to step this through a debugger, you could check if your `lea / mov` combo is working right. Either way, I would expect 1 or 10, not 11. Maybe you meant to `add` instead of` `mov`? – Michael Dorgan Mar 15 '17 at 20:39
  • after call _InitPoiner I added pop [variable1] and it's works. – Alatriste Mar 15 '17 at 20:41
  • sorry I meant to add instead of mov. – Alatriste Mar 15 '17 at 21:07
  • Just for the sake of completeness: You were assuming a _callee stack-cleanup convention_, but implemented a _caller stack-cleanup convention_. By cleaning up the stack you have efficiently fixed this problem by yourself. See [WikiPedia on calling-conventions](https://en.wikipedia.org/wiki/X86_calling_conventions#List_of_x86_calling_conventions) to understand why you have fixed your problem on your own. – zx485 Mar 15 '17 at 21:07
  • why I can "do not POP array after PUSH_ing him" ? push my_array call my_func; push my_array call my_func – Alatriste Mar 15 '17 at 21:12
  • Ok, moving my comment to an answer then since it seems to have got you on the right track :) – Michael Dorgan Mar 15 '17 at 21:35

2 Answers2

3

You are making sure that you pop your vars when done?

Looking at your example, I see no way that the variable could ever be 11. It starts as 1 at the dd assignment, then if your math in the lea is correct, it would then be 10. If you were to step this through a debugger, you could check if your lea / mov combo is working right. Either way, I would expect 1 or 10, not 11.

Maybe you meant to add instead of mov?

Michael Dorgan
  • 12,453
  • 3
  • 31
  • 61
3

The main problem is that you are not pushing the address of variable1 onto the stack when you do push [variable1]. That pushes the 32-bit value stored at variable1 which happens to be the value of 1. To push the address you would use push variable1 without the brackets.

When pushing values onto the stack before a call you need to restore the stack after the call.

LEA wasn't getting the address stored on the stack but getting the address of the stack location where the address should have been stored. I think you were looking for something like:

format ELF

extrn printf
public main

section '.text' executable
main:
    push variable1         ; push address of variable
    call _InitPointer
    add esp, 4             ; We pushed 4 bytes before calling function
                           ; restore the stack by adding 4

    push [variable1]       ; Push the value at address variable1
    push sdigit            ; Format specifier for printf
    call printf
    add esp, 8             ; We pushed 8 bytes of data for call
                           ; restore the stack by adding 8
    ret

_InitPointer:
    push ebp
    mov ebp, esp

    mov eax, [ebp+8]       ; There is an address at [ebp+8] that
                           ; was pushed as the 1st parameter. Put the
                           ; address in EAX

    add dword [eax], 10    ; Add the value 10 to the DWORD value that is at
                           ; address in EAX

    pop ebp
    ret

section '.data' writeable
variable1 dd 1
sdigit db '%d', 0x0D, 0x0A, 0

You didn't mention the platform you are on as you didn't supply a minimal complete verifiable example. The code above could be tested on Linux with:

fasm test.asm
gcc -o test -m32 test.o

When run you should get:

11

The equivalent C code would look like:

#include <stdio.h>

void _InitPointer (int *ptr)
{
    *ptr += 10;
    return;
}

int variable1 = 1;

int main()
{
    _InitPointer (&variable1);
    printf ("%d\n", variable1);
    return 0;
}

Note: If on modern versions of Linux, 32-bit programs follow System V i386 ABI that requires the stack be 16-byte (or 32-byte) aligned at the point of a function call. I didn't do that in the code above to keep it simplified but it should be taken into account. I'm unsure if you are on Linux or Windows. Your question doesn't say.


32-bit Windows Version

format PE console 4.0
include 'win32a.inc'

main:
    push variable1         ; push address of variable
    call _InitPointer
    add esp, 4             ; We pushed 4 bytes before calling function
                           ; restore the stack by adding 4

    push [variable1]       ; Push the value at address variable1
    push sdigit            ; Format specifier for printf
    call [printf]
    add esp, 8             ; We pushed 8 bytes of data for call
                           ; restore the stack by adding 8
    push 0                 ; Exit with return value 0
    call [ExitProcess]

_InitPointer:
    push ebp
    mov ebp, esp

    mov eax, [ebp+8]       ; There is an address at [ebp+8] that
                           ; was pushed as the 1st parameter. Put the
                           ; address in EAX

    add dword [eax], 10    ; Add the value 10 to the DWORD value that is at
                           ; address in EAX

    pop ebp
    ret

variable1 dd 1
sdigit db '%d', 0x0D, 0x0A, 0

data import
 library kernel32,'KERNEL32.DLL',\
         msvcrt,'MSVCRT.DLL'
 import msvcrt,\
        printf ,'printf'
 import kernel32,\
        ExitProcess,'ExitProcess'
end data
Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • I'm on Windows. – Alatriste Mar 16 '17 at 06:32
  • You said "LEA wasn't getting the address stored on the stack but getting the address of the stack location where the address should have been stored." so if `push [variable]` is not sending address of variable, then how it was working properly? I guess `lea eax, dword[ebp+8]` was loading stack's address where was VALUE of `variable`, then `mov dword [eax], 10' was loading 10 into stack address where is that value, but how original `variable' changed? Because when we are sending parameter by value, compilator making copy (from C) – Alatriste Mar 16 '17 at 06:41
  • @Alatriste `push [variable1]` was pushing `variable1` by value. That placed the value 1 on the top of the stack (not the address of variable1). `lea eax, dword[ebp+8]` moved the address where the value 1 was stored on the stack (not the actual location of `variable1`) into _EAX_. You then modified the value on the stack with the `add`. Upon returning `pop [variable1]` then takes the modified value off the top of the stack and stores (copies) it to the memory address of `variable1`. Although this works, this is not how you usually pass a pointer to a function. – Michael Petch Mar 16 '17 at 06:53
  • @Alatriste This is the reason your code didn't work until you did `pop [variable1]` because your function never actually modified the value at the memory address containing `variable1` – Michael Petch Mar 16 '17 at 06:53
  • Now I understand, so: `lea eax, dword [ebp+8]` was loading address of the stack where was value 1. Then `add` was adding value 10 into that address (stack adress), then `pop [variable1]` was loading top of the stack (i.e value 11) into `variable1` and then incrementing `esp` register. So that `pop` was doing copying BUT NOT function. – Alatriste Mar 16 '17 at 06:57
  • 1
    @Alatriste : yes – Michael Petch Mar 16 '17 at 06:58