简体   繁体   中英

Assembly MASM - Print dynamic array the correct way and saving it on the heap

I wrote a simple program that takes an array length, populate the array by storing it at using esp decrement (so on the stack) then it print the array. My code is the following:

.686
.xmm
.model flat, C
OPTION CaseMap:None

include ../masm32/libs/windows.inc
include ../masm32/libs/kernel32.inc
include ../masm32/libs/user32.inc
include ../masm32/libs/msvcrt.inc
include ../masm32/libs/masm32.inc

EXTERN printf:PROC
EXTERN scanf:PROC

.data
    str_insert_array_length db  "Insert Array Length: ",0
    str_insert_value    db  10,"Insert Value: ",0
    str_input_format    db  "%d",0
    str_format_print    db  "%d",10,0

    input_length   DWORD    0
    input_value    DWORD    0

.code

main PROC
    push ebp
    mov ebp,esp

    push offset str_insert_array_length
    call printf
    add esp,4

    push offset input_length
    push offset str_input_format
    call scanf
    add esp,8
    
    mov edi,[input_length]

array_input:
    push offset str_insert_value
    call printf
    add esp,4

    push offset input_value
    push offset str_input_format
    call scanf
    add esp,8

    mov eax, [input_value]
    push eax

    dec edi
    jnz array_input


    mov edi,[input_length]
    sub esp,4
print_array:
    mov edx,[esp+4*edi]
    push edx
    push offset str_format_print
    call printf
    add esp,8
    dec edi
    jnz print_array

    add esp,4


    pop ebp
    invoke ExitProcess,0
main ENDP
    end

As you can see before the "print_array" part I need to sub esp by 4 because otherwise I get the current return address printed as the first element of the array (because it will be "esp+20" and the array starts at "esp+16") instead of the last element printed. After the part I add 4 to esp to get it to the right position again. Is that the correct way to print the array or there is another method instead of sub/add esp by 4 before/after the code part?

Also if I want to save the array on the Heap, how can I do it? I know I need to declare a variable, but this variable should have dynamic length because the length of the array is dynamic so I don't know how to get this:/

As you can see before the "print_array" part I need to sub esp by 4 because otherwise I get the current return address printed as the first element of the array (because it will be "esp+20" and the array starts at "esp+16") instead of the last element printed.

Your offsets tell me that you inputted 5 numbers for the array. Your stack will have looked like:

5,0,0,0,4,0,0,0,3,0,0,0,2,0,0,0,1,0,0,0,x,x,x,x,y,y,y,y
^                                       ^       ^
ESP                                     Old EBP Return address

Without sub esp, 4 you would have retrieved the preserved value of EBP and not the current return address as you say.

After the part I add 4 to esp to get it to the right position again. Is that the correct way to print the array or there is another method instead of sub/add esp by 4 before/after the code part?

There's no wrong of right here, but you could have solved it without sub / add

  • if you would have added a correcting displacement of -4 to the instruction that loads EDX:

     mov edi, [input_length] print_array: mov edx, [esp + 4*edi - 4]... dec edi jnz print_array
  • or if you would have considered array indexes to be zero-based quantities:

     mov edi, [input_length]; eg. Array has 5 elements dec edi; eg. Highest element has index 4 print_array: mov edx, [esp + 4*edi]... dec edi; Lowest element has index 0 jns print_array; Continue for all positive indexes

Also if I want to save the array on the Heap, how can I do it?

If you need to go that way then read about it in Dynamic Heap Memory in x86 Assembly MASM .


Below is a version of the code that allocates the required space for the array on the stack in a single operation, and that stores the array elements in the normal order (which is easier to work with):

    push ebp
    mov  ebp, esp

; Prompt for the number of elements
    push offset str_insert_array_length
    call printf
    push offset input_length
    push offset str_input_format
    call scanf
    add  esp, 4 + 8             ; Combining both clean-ups

; Make room on the stack based on the number of elements
    mov  eax, [input_length]    ; eg. 5
    shl  eax, 2                 ; Is times 4 (size of integer)
    sub  esp, eax               ; eg. Minus 20

; Input the elements in the space between ESP and EBP
    mov  edi, esp
array_input:
    push offset str_insert_value
    call printf
    push edi                    ; No need to go via an extra variable!
    push offset str_input_format
    call scanf
    add  esp, 4 + 8

    add  edi, 4
    cmp  edi, ebp
    jb   array_input

; Print the elements from the space between ESP and EBP
    mov  edi, esp
print_array:
    mov  edx, [edi]
    push edx
    push offset str_format_print
    call printf
    add  esp, 8

    add  edi, 4
    cmp  edi, ebp
    jb   print_array

    pop ebp

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM