2
\$\begingroup\$

Module 1:

;******************************************************************************* ; A generic Linked List ADT for any datatype. ; ; Author: William .386 .MODEL flat, stdcall .STACK 4096 PUBLIC push_front, print_list ; Win32 function prototypes and synonyms GetProcessHeap PROTO HeapAlloc PROTO, hHeap:DWORD, dwFlags:DWORD, dwBytes:DWORD GetStdHandle PROTO, nStdHandle:DWORD WriteConsoleA PROTO, hConsoleOutput:DWORD, lpBuffer:PTR DWORD, nNumberofCharsToWrite:DWORD, lpNumberOfCharsWritten:PTR DWORD, lpReserved:DWORD STD_OUTPUT_HANDLE equ -11 HEAP_ZERO_MEMORY equ 00000008h .CODE ;------------------------------------------------------------------------------- ; print_list(hptr, fptr) ; ; Prints nodes of given linked list ; ; Entry: hptr EQU [ebp + 8] ;head ptr fptr EQU DWORD PTR[ebp + 12] ;std_call func ptr that ; prints list data type ;------------------------------------------------------------------------------- print_list: push ebp mov ebp, esp sub esp, 12 push eax push edx push ebx ; Locals variables arrow EQU [ebp - 4] ;string "-> " mov DWORD PTR arrow, ' >-' nstr EQU [ebp - 8] ;string "NULL" mov DWORD PTR nstr, 'LLUN' wrtn EQU [ebp - 12] ;num of chars written mov DWORD PTR wrtn, 0 ; loop while(node != NULL) mov ebx, hptr jmp endL3 L3: ; print (node->data) push [ebx] call fptr ; print "-> " INVOKE GetStdHandle, STD_OUTPUT_HANDLE mov edx, eax INVOKE WriteConsoleA, edx, ADDR arrow, 3, ADDR wrtn, 0 ;node = node -> next mov ebx, [ebx + 4] endL3: test ebx, ebx jnz L3 ;print "NULL" INVOKE GetStdHandle, STD_OUTPUT_HANDLE mov edx, eax INVOKE WriteConsoleA, edx, ADDR nstr, 4, ADDR wrtn, 0 pop ebx pop edx pop eax mov esp, ebp pop ebp ret 8 ;------------------------------------------------------------------------------- ; push_front(headptr, dataptr, dsiz) ; ; Adds a new linked list node to the front of a linked list. ; ; Entry: hptr EQU [ebp + 8] ;DW ptr to headptr dptr EQU [ebp + 12] ;DW data ptr dsiz EQU [ebp + 16] ;DW data size in bytes node_size EQU 00000008h ;------------------------------------------------------------------------------- push_front: ; set up stack save regs push ebp mov ebp, esp push eax push ebx push ecx push edx push esi ; allocate memory for new node call GetProcessHeap INVOKE HeapAlloc, eax, HEAP_ZERO_MEMORY, node_size mov ebx, eax ;save node in ebx ; allocate memory for new data call GetProcessHeap INVOKE HeapAlloc, eax, HEAP_ZERO_MEMORY, dsiz ; save into new node mov [ebx], eax ;node->data = new data mov eax, hptr mov eax, [eax] ;dereference hptr mov [ebx + 4], eax ;node->next = hptr ; loop copying data into newly allocated ; memory byte per byte mov edx, dsiz mov esi, dptr xor ecx, ecx ;loop counter jmp endL1 L1: mov al, [esi + ecx] mov [ebx + ecx], al inc ecx endL1: cmp ecx, edx jl L1 ; hptr = new node mov eax, hptr mov [eax], ebx ; restore regs clean up stack pop esi pop edx pop ecx pop ebx pop eax pop ebp ret 12 END 

Module 2

;******************************************************************************* ; LL_main.asm is the main module that demonstrates the Linked_List ADT ; ; Author: William .386 .MODEL flat, stdcall .STACK 4096 EXTERN push_front:near, print_list:near ; Win32 API function prototypes and synonyms ExitProcess PROTO, dwExitCode:DWORD GetStdHandle PROTO, nStdHandle:DWORD WriteConsoleA PROTO, hConsoleOutput:DWORD, lpBuffer:PTR DWORD, nNumberofCharsToWrite:DWORD, lpNumberOfCharsWritten:PTR DWORD, lpReserved:DWORD STD_OUTPUT_HANDLE EQU -11 NULL EQU 0 .CODE ;------------------------------------------------------------------------------- ; print_hex(num) ; ; prints a 32 bit unsigned hexadecimal number to the console ; ; Entry: num EQU [ebp + 8] ; DW unsigned hex number ;------------------------------------------------------------------------------- print_hex: ; set up stack frame, save regs push ebp mov ebp, esp sub esp, 4 push eax push ebx push edx push esi ; local variable for # of chars written by WriteConsoleA nWrtn EQU [ebp - 4] mov DWORD PTR nWrtn, 0 ; This loop repeatedly divides the number by 10h, converts the remainder ; to its corresponding ASCII code, and then saves the char to the stack mov eax, num mov ebx, 10h ; the divisor, 10h xor edx, edx ; clear edx xor esi, esi ; esi = num of chars L1: div ebx ; div num by 10h ;convert remainer to ASCII code ;if edx > 9, add 7 cmp edx, 9 jle endIf1 add edx, 7 endIf1: ;add char '0' to num add edx, '0' ;put char on stack dec esp ; allocate stack space mov [esp], dl ; save char to stack inc esi ; inc num of chars xor edx, edx ; clear edx ; end of loop L1 test eax, eax ; loop while num != 0 jnz L1 ; print out chars from the stack mov edx, esp INVOKE GetStdHandle, STD_OUTPUT_HANDLE mov ecx, eax INVOKE WriteConsoleA, ecx, edx, esi, ADDR nWrtn, NULL add esp, esi ; restore esp ; ;clean up stack, restore regs pop esi pop edx pop ebx pop eax mov esp, ebp pop ebp ret 4 ;------------------------------------------------------------------------------- ; main() ; ; creates a linked list of integers and prints them to the screen. ;------------------------------------------------------------------------------- main: mov ebp, esp sub esp, 8 ; local variables head_ptr EQU [ebp - 4] ; head of list mov DWORD PTR head_ptr, 0 hex_int EQU [ebp - 8] ; a starting int mov DWORD PTR hex_int, 10fd134h ; loop L2 adds 6 numbers to list xor esi, esi ; loop counter L2: ; add hex_int to front of the list push 4 lea eax, hex_int push eax lea eax, head_ptr push eax call push_front inc esi add DWORD PTR hex_int, 14768h ; end of L2 cmp esi, 6 ; while (esi < 6) jl L2 ; print out list push print_hex push head_ptr call print_list mov esp, ebp INVOKE ExitProcess, 0 END main 

Output:

116363C-> 114EED4-> 113A76C-> 1126004-> 111189C-> 10FD134-> NULL

This is a minimal implementation of a Linked List that took me a long time to figure out and get working. It only allows you to create a list, push to it, and print it out. There is no way to destroy the list, so the program leaks memory.

I'm looking for ALL criticism.

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

The print_hex procedure preserves almost all registers, yet you didn't preserve the ECX register that you nonetheless used in mov ecx, eax.

Maybe an idea to use pushad and popad:

num EQU [ebp + 36] nWrtn EQU [ebp - 4] ;----------------------------------------------- print_hex: ; set up stack frame, save regs pushad mov ebp, esp ... mov esp, ebp popad ret 4 

Instead of initializing the local variable with sub esp, 4 mov DWORD PTR nWrtn, 0 you can simply write:

 xor eax, eax push eax 

The hex conversion should not be done using division at all! Remember that dividing by 16 is just shifting 4 times to the right.
Next is an optimized version:

 mov ebx, 'A' - 10 mov ecx, num xor esi, esi ; esi = num of chars L1: mov eax, ecx and eax, 15 ; Keep lowest nibble mov edx, '0' cmp eax, 9 cmova edx, ebx ; Only for [10,15] will EDX become 55 add eax, edx ; Either [0,9] + 48 or [10,15] + 55 dec esp ; allocate stack space mov [esp], al ; save char to stack inc esi ; inc num ofchars shr ecx, 4 ; loop while num != 0 jnz L1 

Allocating single bytes on the stack (any number of bytes from 1 to 8), leaves the stackpointer un-aligned! Always keep ESP dword aligned.

 mov edx, esp and esp, -4 ; Keep ESP dword aligned INVOKE GetStdHandle, STD_OUTPUT_HANDLE 

To restore ESP use EBP

 mov esp, ebp popad ret 4 

 xor esi, esi ; loop counter L2: ... inc esi cmp esi, 6 ; while (esi < 6) jl L2 

Since ESI holds a counter that will always be positive, I think using the unsigned conditional jump would be more appropriate.

 cmp esi, 6 ; while (esi < 6) jb L2 

Better still, count downward and shave off the cmp instruction. You can do this because the ESI value here isn't used for anything else than the loop count.

 mov esi, 6 L2: ... dec esi jnz L2 

The loop that copies memory a byte at a time can be simplified if the copying starts at the high end. And because it's a safe assumption that dsiz will always be positive non-zero you can code a Repeat-Until loop instead of a While loop.

; loop copying data into newly allocated memory byte per byte mov edx, dsiz ; 4 is your example mov esi, dptr L1: dec edx mov al, [esi + edx] mov [ebx + edx], al jnz L1 ; Flags still set according to "dec edx" 
\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.