Search code examples
windowsassemblyx86-64nasm

Subtract or add a number from a variable in the bss segment in windows x64 assembly


default rel
bits 64

segment .data
    username                     db "saave",  0
    password                     db "root", 0

    information_text_username    db "please enter your username: ", 0 
    information_text_passw       db "please enter your password: ", 0
    
    not_equal                    db "username or password is incorrect", 0xa, 0

    entrance                     db "WELCOME TO SEA BANK", 0xa, 0
    option1                      db "1-Show Balance",      0xa, 0
    option2                      db "2-Withdraw Money",    0xa, 0
    option3                      db "3-Deposit Money",     0xa, 0
    option0                      db "exit",                0xa ,0
    ;option4                     db "calculate interest",  0xa

    userchoice0                  db "0", 0
    userchoice1                  db "1", 0
    userchoice2                  db "2", 0
    userchoice3                  db "3", 0
    ;userchoice4                 db "4", 0

    information_text_choice      db "Please choose your operation: ",          0
    information_text_userchoice1 db "Current balance: ",                       0
    information_text_userchoice2 db "Enter the amount you want to withdraw: ", 0
    information_text_userchoice3 db "Enter the amount you want to deposit: ",  0

    new_balance                  db "new balance: %d", 0

    fmt_s                        db "%s", 0
    fmt_d                        db "%d", 0

segment .bss
    money:     resb 8       ; defined money
    user_name: resb 8       ; defined username
    pass_word: resb 8       ; defined password
    choose:    resb 8       ; defined choose
    withdraw_amount: resb 8 ;
    deposit_amount: resb 8  ;

segment .text

extern printf, scanf, strcmp, ExitProcess, _CRT_INIT

global main

exit:
    xor rax, rax
    call ExitProcess

hello_system:
    lea rcx, [option1]
    call printf
    mov rax, 0

    lea rcx, [option2]
    call printf
    mov rax, 0

    lea rcx, [option3]
    call printf
    mov rax, 0

    jmp user_choices

    ;lea rcx, [option4]
    ;call printf

user_check:
    lea rcx, [information_text_username]
    call printf; information text for username
    mov rax, 0

    lea rcx, [fmt_s]
    mov rdx, user_name
    call scanf; get username
    mov rax, 0 

    lea rcx, [information_text_passw]
    call printf; information text for password
    mov rax, 0

    lea rcx, [fmt_s]
    mov rdx, pass_word
    call scanf; get password
    mov rax, 0

    lea rcx, [username]
    mov rdx, user_name
    call strcmp; compare usernames

    test eax, eax
    jne not_equal_credentials; if not equal jump to func
    

    lea rcx, [password] 
    mov rdx, pass_word
    call strcmp; compare passwords

    test eax, eax
    jne not_equal_credentials ; if not equal jump to func

    ;otherwise

    lea rcx, [entrance] 
    call printf ;welcome sea bank
    mov rax, 0

    jmp hello_system

user_choices:
    lea rcx, [information_text_choice]
    call printf; information text for user choices
    mov rax, 0

    lea rcx, [fmt_s]
    mov rdx, choose
    call scanf; user input for choice number
    mov rax, 0

    lea rcx, [choose]
    mov rdx, userchoice1
    call strcmp
    
    test eax, eax
    je choice_1
    ;jmp user_choices

    lea rcx, [choose]
    mov rdx, userchoice2
    call strcmp

    test eax, eax
    je choice_2

    lea rcx, [choose]
    mov rdx, userchoice3
    call strcmp

    test eax, eax
    je choice_3
    
    lea rcx, [choose]
    mov rdx, userchoice0
    call strcmp

    test eax, eax
    je exit

    ;lea rcx, choose
    ;mov rdx, userchoice4
    ;call strcmp

choice_1:
    lea rcx, information_text_userchoice1
    call printf
    mov rax, 0

    lea rcx, [fmt_d]
    mov rdx, money
    call printf; print money
    mov rax, 0

    jmp user_choices

choice_2:
    lea rcx, [information_text_userchoice2]
    call printf
    mov rax, 0

    lea rcx, [fmt_d]
    mov rdx, withdraw_amount
    call scanf
    mov rax, 0

    mov eax, withdraw_amount
    sub ecx, eax
    mov eax, ecx
    mov [money], eax

    lea rcx, [new_balance]
    mov rdx, money
    call printf

    jmp user_choices
    
choice_3:
    lea rcx, [information_text_userchoice3]
    call printf
    mov rax, 0

    lea rcx, [fmt_d]
    mov rdx, deposit_amount
    call scanf
    mov rax, 0

    mov eax, deposit_amount
    add ecx, eax
    mov eax, ecx
    mov [money], eax

    jmp user_choices

not_equal_credentials:
    lea rcx, [not_equal]
    call printf
    mov rax, 0
    jmp user_check

main:
    push rbp
    mov rbp, rsp
    sub rsp, 32

    mov ecx, [money]
    
    jmp user_check

I wanted to write a simple banking system, I can't see any problem in the user login or other parts, but the value of the money variable in the bss segment does not change at all when I try to add or remove money.
Also, when I first run the program, I think it shows a different number as the output when I choose the 1st option. It happens because I don't specify, how can I fix these two problems?

I use these two commands to compile.

1

-nasm -f win64 -o "main.obj" "main.asm"

2

-link "C:\Users\xx\Desktop\assembly_x64\bank_system\main.obj" /subsystem:console /entry:main /defaultlib:ucrt.lib /defaultlib:msvcrt.lib /defaultlib:legacy_stdio_definitions.lib /defaultlib:Kernel32.lib /nologo /incremental:no /LARGEADDRESSAWARE:NO /opt:ref /out:"main.exe"


Solution

  • When the user chooses to "Withdraw Money", you execute the following code:

    mov eax, withdraw_amount
    sub ecx, eax
    mov eax, ecx
    mov [money], eax
    

    Two problems here:

    • The ECX register at this point does not contain the current balance.
    • You are subtracting the address of the withdraw_amount variable instead of its value. (this also answers your second question)

    Solve it with next simple code:

    mov  eax, [withdraw_amount]
    sub  [money], eax
    

    or (avoiding Read-Modify-Write sub) with:

    mov  eax, [money]
    sub  eax, [withdraw_amount]
    mov  [money], eax
    

    The same issue exists for when the user chooses to "Deposit Money".

    In your defense, you could have been thinking that the current balance was already in the ECX register since you do have a mov ecx, [money] right at the start of the program. Sadly, by the time the calculations happen, the ECX register will have been used for a lot of other things already!