Search code examples
linuxassemblyx86

X86 Assembly - Structure Points - Not Storing/Returning Correctly?


I just started working with structure points and it's quite confusing.

The Program is supposed to let a user enter 5 values, save it in the STRUC Point and then return what the values are.

The "read_loop" reads the users inputs and sends it to readInt to be translated to ASCII, then when returned it's saved using "mov [esi + Point.x], eax" and "mov [esi + Point.y], eax" then the "read_loop should print back out those values in a loop.

This is the expected output.

Enter x and y values for point: 
53
6
Enter x and y values for point: 
3
6
Enter x and y values for point: 
3
6
Enter x and y values for point: 
3
6
Enter x and y values for point: 
3
6
Point values: 
53
6
Point values: 
3
6
Point values: 
3
6 
Point values: 
3
6 
Point values: 
3
6 

However this is the output I'm getting

Enter x and y values for point: 
53
6
Enter x and y values for point: 
3
6
Enter x and y values for point: 
3
6
Enter x and y values for point: 
3
6
Enter x and y values for point: 
3
6
Point values: 
 
Point values: 
 
Point values: 
 
Point values: 
 
Point values: 
 

For some reason it's either not storing the values correctly, or isn't grabbing the values correctly? I've been trying to troubleshoot it for hours, I tried messing with ALIGN and I can't see what's causing the values to not be returned.

Here is the complete code

STRUC Point ; define point structure
    .x: RESD 1 ;reserve 4 bytes for x coordinate 
    .y: RESD 1 ;reserve 4 bytes for y coordinate
    .size:
ENDSTRUC

section .data
    enter_msg db 'Enter x and y values for point: ',10, 0
    enter_msg_len: equ $-enter_msg
    space db ' ', 0
    output_msg db 'Point values: ', 10, 0
    output_msg_len: equ $-output_msg

   

section .bss
    PtArr: RESB Point.size*5 ; reserve place for 5 structures
    ArrCount: EQU ($-PtArr) / Point.size ; Should be 5 structures

section .text
    global _start

_start:

    push ebp            ; Save ebp for whoever called main function (OS or other program)
    mov ebp, esp        ; Create our new stack frame

    ; Initialize esi register to point to the start of PtArr
    lea esi, [PtArr]


    mov ebx, 5  ; Initialize loop counter with the desired number of iterations

read_loop:
    mov ecx, enter_msg       ; Print message #1
    mov edx, enter_msg_len
    call printString

; Read x value
call readInt
mov [esi + Point.x], eax
; Debugging print statement
mov ecx, [esi + Point.x]
call printDec
call printNewLine

; Read y value
call readInt
mov [esi + Point.y], eax
; Debugging print statement
mov ecx, [esi + Point.y]
call printDec
call printNewLine

add esi, Point.size     ; Increment pointer to next structure in array
    
    add esi, Point.size     ; Increment pointer to next structure in array
    dec ebx                 ; Decrement loop counter
    jnz read_loop           ; Jump to beginning of loop if counter is not zero

jmp prepare_print_loop  ; Jump to prepare_print_loop to reset esi and then jump to print_loop

jmp prepare_print_loop  ; Jump to prepare_print_loop to reset esi and then jump to print_loop
prepare_print_loop:
    ; Reset esi to point to the start of PtArr
    lea esi, [PtArr]

    ; Initialize loop counter with the desired number of iterations (5 in this case)
    sub ebx, ebx
    mov ebx, 5

    ; Debugging print loop
    mov ecx, output_msg       ; Print message #2
    mov edx, output_msg_len
    call printString
    mov ecx, [esi + Point.x]
    call printDec
    mov ecx, space
    call printString
    mov ecx, [esi + Point.y]
    call printDec
    call printNewLine

print_loop:
    ; Display output message
    mov ecx, output_msg       ; Print message #2
    mov edx, output_msg_len
    call printString

    ; Save the value of esi
    push esi

    ; Print x value
    mov eax, [esi + Point.x]
    call printDec

    ; Print space
    mov ecx, space
    mov edx, 1
    call printString

    ; Print y value
    mov eax, [esi + Point.y]
    call printDec

    ; Print newline
    call printNewLine

    ; Restore the value of esi
    pop esi

    ; Increment to the next structure
    add esi, Point.size
    dec ebx
    jnz print_loop

jmp code_exit



code_exit:
    ; Exit the program
    mov eax, 1
    xor ebx, ebx
    int 0x80




readInt:
    ; Save register values of the called function
    pusha

    ; Allocate buffer for input
    sub esp, 16

    ; Read input from the user (system call 3)
    mov eax, 3
    xor ebx, ebx
    lea ecx, [esp]
    mov edx, 15
    int 0x80

    ; Convert string to integer
    xor eax, eax
    xor edi, edi
    lea edi, [esp]

.str_to_int_loop:
    cmp byte [edi], 10 ; Check for newline character
    je .str_to_int_done

    ; Multiply eax by 10
    lea ecx, [eax * 2 + eax] ; ecx = eax * 3
    lea eax, [ecx * 2 + ecx] ; eax = ecx * 3 + ecx = eax * 9

    ; Subtract ASCII '0'
    sub byte [edi], '0'
    add al, byte [edi]

    inc edi
    jmp .str_to_int_loop

.str_to_int_done:
    ; Restore stack and register values
    add esp, 16
    popa
    ret








    
printString:
    ;Save register values of called function
    pusha

    mov eax, 4  ;use 'write' system call = 4
    mov ebx, 1  ;file descriptor 1 = STDOUT
    int 80h     ;call the kernel

    ;restore the old register values of the called function
    popa
    ret



; Add printNewLine function
section .data
    nl db "", 10
section .text
printNewLine:
    ;save register values of the called function
    pusha
    mov ecx, nl
    mov edx, 1
    mov eax, 4
    mov ebx, 1
    int 0x80

    ;restore the old register values of the called function
    popa 
    ret



printDec:
    section .bss
        decstr resb 10;
        ct1 resd 1

    section .text
        pusha ;save all registers

        ; Save the value of edi
        push edi

        mov dword[ct1], 0 ; assume initially 0
        mov edi, decstr ;edi points to dec-string in memory
        add edi, 9 ;moved to the last element of string
        xor edx, edx

whileNotZero:
        mov ebx, 10 ;get ready to divide by 10
        div ebx ;divide by 10
        add edx,'0' ; convert to ascii char
        mov byte[edi], dl ; put it in string
        dec edi ;move to next char in string
        inc dword[ct1]
        xor edx, edx ;clear edx
        cmp eax, 0 ;is remainder 0
        jne whileNotZero ; keep looping

        ; Restore the value of edi
        pop edi

        inc edi ; conversion finish
        mov ecx, edi
        mov edx, [ct1]
        mov eax, 4
        mov ebx, 1
        int 0x80

        popa ;restore registers
        ret



Tried using ALIGN, checked to make sure it's storing properly.


Solution

  • List of problems in the code

    ; Debugging print statement
    mov ecx, [esi + Point.x]
    call printDec
    

    The argument to printDec goes in EAX. This mis-hap occurs 4 times.

    add esi, Point.size     ; Increment pointer to next structure in array
    add esi, Point.size     ; Increment pointer to next structure in array
    

    A redundant second addition. To be removed.

    jmp prepare_print_loop  ; Jump to prepare_print_loop to reset esi and then jump to print_loop
    jmp prepare_print_loop  ; Jump to prepare_print_loop to reset esi and then jump to print_loop
    prepare_print_loop:
    

    Both these jumps are redundant.

    mov ecx, space
    call printString
    

    The required EDX argument was not given.

    jmp code_exit
    code_exit:
    

    A redundant jump but fine in case of future additions to the program.

    ; Multiply eax by 10
    lea ecx, [eax * 2 + eax] ; ecx = eax * 3
    lea eax, [ecx * 2 + ecx] ; eax = ecx * 3 + ecx = eax * 9
    

    You're 1 time short here! Times 10 is simple imul eax, 10.

    ; Subtract ASCII '0'
    sub byte [edi], '0'
    add al, byte [edi]
    

    The carry needs to propagate through the whole EAX.
    You could write movzx edx, byte [edi] sub edx, '0' add eax, edx.


    Because of pusha ... popa, readInt isn't returning anything in the EAX register.

    .str_to_int_done:
        ; Restore stack and register values
        add  esp, 16
        mov  [esp+28], eax    ; Return EAX through overwriting pushad.EAX
        popa
        ret
    

    ; Save the value of edi
    push edi
    ...
    ; Restore the value of edi
    pop edi
    

    In printDec, the separate preserving of EDI is not only redundant but also harmful. To be removed.