Question

I'm trying to implement a linked list in assembly, so I have an 'array' (actually 20 bytes) to save the link for 5 possible lists. each 'link' is 5 bytes long (1 for data 4 for pointer - x86 machine). Now I called malloc and created 1 link and pushed a number into the first byte (decimal number) and moved the link pointer to the start of the array. after that I try to call malloc again to create a new link but the new link created overwrites the link I have allready pushed into the array and I have no idea why!!!. here is the code and some input/output examples:

section .rodata
LC0:
    DB  "The number is: %i", 10, 0  ;  string

LC1:
    DB  "Memory allocation failed!!!", 10, 0    ;  string


section .data
section .bss

numbers_stack:
    RESB    20

link:
    RESB    link_size   

section .text
align 16
global main
extern printf
extern malloc
extern gets
link_size EQU 5

_start:
jmp main 

main:

%macro  mymalloc 2  ;malloc macro
mov edx, %1 ; size to allocate
push edx
call malloc
add esp,4
test eax,eax
jz fail_exit
mov [%2], eax
%endmacro

%macro myprintf 1 ;printing macro
push %1
push LC0
call printf
add esp,8
%endmacro

mymalloc link_size,link
mov byte[link], 44
mov dword[numbers_stack],link

mov eax,0
mymalloc link_size,link ; allocate new link - *at this point the contents are allready overwritten

mov eax,[numbers_stack] ; get pointer to list head from numbers_array[0] into eax
mov edx,0
mov dl,byte[eax]
myprintf edx

output examples: it will always print out the number '40' where its supposed to print out '44' if i delete the second mymalloc it will print 44 as expected, please help! why is it still pointed to the old memory location when I obviously allocated a new one?!

Was it helpful?

Solution

You are basically missing one level of indirection. malloc will return a pointer that you store in link (thus it's size should be 4, not link_size). Then, when you do mov byte[link], 44 you are overwriting this pointer and not writing into the allocated memory region. You need to load the pointer into a register (but of course malloc already returned it in eax) and then dereference that, such as:

mov eax, [link]
mov byte [eax], 44

You will also need to adjust the pointer there and you don't need the numbers_stack at all, lists just have a head pointer. You might want to use the common established names such as head, next and node so that others can more easily understand what you are talking about.

PS: if you are using libc functions you should use entry point main and not _start and link with all the necessary startup objects so that libc has a chance to initialize properly. You should finally just ret from main, or use the exit function but not the exit syscall.


Update: here is a possible implementation that allocates 2 lists and prints the first value from each:

section .rodata
LC0:
    DB  "The number is: %i", 10, 0  ;  string
LC1:
    DB  "Memory allocation failed!!!", 10, 0    ;  string

section .bss

struc node
    .next resd 1
    .value resb 1
endstruc

list_heads:
    RESD    5

section .text
global main
extern printf
extern malloc
extern gets

main:

%macro  mymalloc 1  ;malloc macro
push %1 ; size to allocate
call malloc
add esp,4
test eax,eax
jz fail_exit
%endmacro

%macro myprintf 1 ;printing macro
push %1
push LC0
call printf
add esp,8
%endmacro

mymalloc node_size
mov [list_heads], eax
mov dword [eax + node.next], 0
mov byte [eax + node.value], 44

mymalloc node_size
mov [list_heads + 4], eax
mov dword [eax + node.next], 0
mov byte [eax + node.value], 11

mov eax, [list_heads] ; get pointer to first list head
movzx edx, byte [eax + node.value]
myprintf edx

mov eax, [list_heads + 4] ; get pointer to second list head
movzx edx, byte [eax + node.value]
myprintf edx

Hope this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top