I am trying to store a command line argument passed to my simple assembly language program in a variable for later use.
global _start
section .text
_start:
pop rax ; argc
cmp rax,1 ; no command line arguments supplied
jz begin
get_cmdln_args:
pop rax ; argv
pop rax ; arg[1]
cmp byte [rax], '-'; test string first char for - character
jz parse_option ;
pop rax ; arg[2]
pop rax ; arg[3]
parse_option:
cmp byte [rax +1], 'p'
jz portarg
portarg:
pop rax
mov [port], rax
portargl:
cmp byte [rax], $0
jz get_cmdln_args
inc rax
jnz portargl
begin:
mov rax, 1 ; write(
mov rdi, 1 ; STDOUT_FILENO,
mov rsi, msg ; "Hello, world!\n",
mov rdx, msglen ; sizeof("Hello, world!\n")
syscall ; );
mov rax, 60 ; exit(
mov rdi, 0 ; EXIT_SUCCESS
syscall ; );
section .bss
port: resb 8
section .rodata
msg: db "Hello, I am from the Isle of Mann!", 10
msglen: equ $ - msg
The problem comes with the portarg label.
In GDB I can see that the value of RAX is "8080" which is what is specified on the command line such that
gdb --args hello -port 8080
launches the debugger and I can see the command line arguments on the stack. After I pop the stack I can see the command line argument in RAX.
After the mov instruction is executed I can still see the "8080" in RAX but what is stored in my variable looks sus.
The address of the variable is 0x403024
x/s 0x403024
returns
"\222\342\377\377\377\177"
What is going on here?
How can I store this as an integer at this address? I have seen examples where you do this
sub RAX, '0'
to remove the trailing 0 and then it is treated as an integer. If I try it here I get an empty string.
The misunderstanding is that you try to store the command line argument as an integer in your memory. Nevertheless it is represented by a string if you use 'pop rax'. The solution is fairly easy: you need to manually convert the string to integer. Make sure to save the calculated value as a quadword. The essential routine could look like this:
str_to_int:
; Convert a null-terminated string in rdi to an integer in rax
xor rax, rax ; Clear rax to store the result
xor rcx, rcx ; Clear rcx to use as a counter
convert_loop:
movzx rbx, byte [rdi + rcx] ; Load the next character
test rbx, rbx ; Check if it's the null terminator
jz done_conversion ; If it is, we are done
sub rbx, '0' ; Convert ASCII to integer
imul rax, rax, 10 ; Multiply current result by 10
add rax, rbx ; Add the new digit
inc rcx ; Move to the next character
jmp convert_loop
done_conversion:
ret