I was reading this assembly tutorial and I got the example to work, so I decided to try to improve it. Once I did so, it stopped working, so I tried to convert it to AT&T syntax so I could compile it with gcc and get debug information (because I'm on OS X, and nasm doesn't generate debug information for the Mach-O format).
I tried to convert the original program that worked, but it stopped working after I wrote it using AT&T syntax. I used gdb to debug it, and found that %rsp
, which I expected to contain argc, contained the value 0x93b2e5ad
. This did not happen with the intel syntax version.
So my question is, why would %rsp
have the incorrect value for argc in the AT&T version, but not in the Intel version?
This the original Intel syntax version (I slightly modified the version in the tutorial):
section .data
WRONG_ARGC db "Must be two command line argument", 0xa
WRONG_ARGC_SIZE equ 34
section .text
global start
start:
pop rcx
cmp rcx, 3
jne argcError
add rsp, 8
pop rsi
call str_to_int
mov r10, rax
pop rsi
call str_to_int
mov r11, rax
add r10, r11
mov rax, r10
xor r12, r12
jmp int_to_str
argcError:
mov rax, 0x2000004
mov rdi, 1
mov rsi, WRONG_ARGC
mov rdx, WRONG_ARGC_SIZE
syscall
jmp exit
; set rdi to exit status before calling
exit:
mov rax, 0x2000001
syscall
str_to_int:
xor rax, rax
mov rcx, 10
next:
cmp [rsi], byte 0
je return_str
mov bl, [rsi]
sub bl, 48
mul rcx
add rax, rbx
inc rsi
jmp next
return_str:
ret
int_to_str:
mov rdx, 0
mov rbx, 10
div rbx
add rdx, 48
; push rdx
dec rsp
mov rsp, rdx
inc r12
cmp rax, 0
jne int_to_str
jmp print
print:
; mov rax, 1
; mul r12
mov rax, r12
; mov r12, 8
; mul r12
mov rdx, rax
mov rax, 0x2000004
mov rdi, 1
mov rsi, rsp
syscall
mov rdi, 0
jmp exit
Here is the code after I converted it to AT&T syntax:
.data
WRONG_ARGC: .ascii "Must be two command line argument\n"
WRONG_ARGC_SIZE: .quad 34
.text
.globl _main
_main:
popq %rcx
cmpq $3, %rcx
jne argcError
addq $8, %rsp
popq %rsi
call str_to_int
movq %rax, %r10
popq %rsi
call str_to_int
movq %rax, %r11
addq %r11, %r10
movq %r10, %rax
xorq %r12, %r12
jmp int_to_str
argcError:
movq $0x2000004, %rax
movq $1, %rdi
movq WRONG_ARGC@GOTPCREL(%rsi), %rsi
movq WRONG_ARGC_SIZE@GOTPCREL(%rsi), %rdx
syscall
jmp exit
# set rdi to exit status before calling
exit:
movq $0x2000001, %rax
syscall
str_to_int:
xorq %rax, %rax
movq $10, %rcx
next:
cmpq $0, (%rsi)
je return_str
movb (%rsi), %bl
subb $48, %bl
mulq %rcx
addq %rbx, %rax
incq %rsi
jmp next
return_str:
ret
int_to_str:
movq $0, %rdx
movq $10, %rbx
divq %rbx
addq $48, %rdx
push %rdx
#decq %rsp
#movq %rdx, %rsp
incq %r12
cmpq $0, %rax
jne int_to_str
jmp print
print:
movq $1, %rax
mulq %r12
movq %r12, %rax
movq $8, %r12
mulq %r12
movq %rax, %rdx
movq $0x2000004, %rax
movq $1, %rdi
movq %rsp, %rsi
syscall
movq $0, %rdi
jmp exit
I compiled the Intel version like this:
nasm -f macho64 -o add_intel.o add_intel.s
ld -o add_intel add_intel.s
And I compiled the AT&T version like this:
gcc -o add_att add_att.s -g