2
\$\begingroup\$

I'm trying to code a simple person database using structs and arrays in assembly.

Each person has a firstName, lastName, age and weight. The goal is to have an infinite loop that asks the user whether they want to read or write to the array then ask them for a position to read or write to. Currently, the array is limited to a max of 5, plan is to increase that (as well as move the request for the position out both the .writing and .reading blocks).

A couple of questions:

  1. Formatting: Is the overall structure of the assembly okay? Any improvements that could be made to the formatting and structure?
  2. Accessing the elements of the array: For simple integer arrays, you can access them with [rax + rcx * (size of int)] where rax is the pointer to the start of the array and rcx is the position in the array we want to access. That didn't work for the Person array; I couldn't use [rax + rcx * Person.size]. So is there a better way to do that access?
  3. Other comments in general?

Compiled as follows using VS2017 x64 Native Tools Command Prompt:

> nasm -g -fwin64 person.asm

> cl /Zi person.obj msvcrt.lib legacy_stdio_definitions.lib

person.asm

default rel

extern scanf
extern printf

STRUC Person
    .first_name: resb 50
    .last_name: resb 50
    .age: resq 1
    .weight: resq 1
    .size:
ENDSTRUC

SECTION .data

    number: dq 0

    scanf_fmt_1: db " %s", 0
    scanf_fmt_2: db " %lld", 0
    scanf_fmt_3: db " %c", 0

    printf_fmt_1: db "Enter a number (1-5): ", 0
    printf_fmt_2: db "Enter a first_name: ", 0
    printf_fmt_3: db "Enter a last_name: ", 0
    printf_fmt_4: db "Enter an age: ", 0
    printf_fmt_5: db "Enter a weight: ", 0
    printf_fmt_6: db "[R]ead or [W]rite? ", 0
    printf_fmt_7: db "Person (%s %s) is %d years old and weights %d", 10, 0

SECTION .bss

    person_array: resb Person.size * 5

SECTION .text

global main
main:
    sub     rsp, 32
.continue_loop:
    lea     rax, [p]                        ; load address of p (or John Doe)

    lea     rcx, [printf_fmt_6]             ; address of "[R]ead or [W]rite? "
    call    printf

    lea     rdx, [number]                   ; address of number variable
    lea     rcx, [scanf_fmt_3]              ; address of " %c"
    call    scanf

    cmp     qword [number], 'W'             ; compare read value against W
    je      .writing                        ; local writing label
    jmp     .reading                        ; local reading label
.writing:
    lea     rcx, [printf_fmt_1]             ; address of "Enter a number (1-5): "
    call    printf

    lea     rdx, [number]                   ; address of number
    lea     rcx, [scanf_fmt_2]              ; address of " %lld"
    call    scanf

    lea     rbx, [person_array]             ; we can't use fancy address calculation so manual it is
    mov     rax, Person.size
    imul    qword [number]
    sub     rax, Person.size                ; we force the user to start at 1, but we start counting at 0
    add     rbx, rax

    lea     rcx, [printf_fmt_2]             ; address of "Enter a first_name: "
    call    printf

    lea     rdx, [rbx + Person.first_name]  ; address of first name
    lea     rcx, [scanf_fmt_1]              ; address of " %s"
    call    scanf

    lea     rcx, [printf_fmt_3]             ; address of "Enter a last_name: "
    call    printf

    lea     rdx, [rbx + Person.last_name]   ; address of last name
    lea     rcx, [scanf_fmt_1]              ; address of " %s"
    call    scanf

    lea     rcx, [printf_fmt_4]             ; address of "Enter an age: "
    call    printf

    lea     rdx, [rbx + Person.age]         ; address of age
    lea     rcx, [scanf_fmt_2]              ; address of " %lld"
    call    scanf

    lea     rcx, [printf_fmt_5]             ; address of "Enter a weight: "
    call    printf

    lea     rdx, [rbx + Person.weight]      ; address of weight
    lea     rcx, [scanf_fmt_2]              ; address of " %lld"
    call    scanf

    jmp .end
.reading:
    lea     rcx, [printf_fmt_1]             ; address of "Enter a number (1-5): "
    call    printf

    lea     rdx, [number]                   ; address of number
    lea     rcx, [scanf_fmt_2]              ; address of " %lld"
    call    scanf

    lea     rbx, [person_array]             ; we can't use fancy address calculation so manual it is
    mov     rax, Person.size
    imul    qword [number]
    sub     rax, Person.size                ; we force the user to start at 1, but we start counting at 0
    add     rbx, rax

    push    qword [rbx + Person.weight]     ; value of weight
    sub     rsp, 32                         ; personal shadow space because > 4 params
    mov     r9, [rbx + Person.age]          ; value of age
    lea     r8, [rbx + Person.last_name]    ; address of last name
    lea     rdx, [rbx + Person.first_name]  ; address of first name
    lea     rcx, [printf_fmt_7]             ; address of "Person (%s %s) is %d years old and weights %d"
    call    printf
.end:
    jmp .continue_loop
    ret
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.