0

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
Addison
  • 3,791
  • 3
  • 28
  • 48
  • 3
    When you use _GCC_ you compiled in the _C_ runtime that does intialaization of the process stack and massages them into _C_ calling convention and then _CALL_ s `_main`. When you use used the start symbol and compiled/linked with NASM and LD you no longer had the _C_ runtime doing the work for you. `start` becomes the entry point for the code. The initial process stack configuration is show in figure 3.9 of the [64-bit System V ABI](http://www.x86-64.org/documentation/abi.pdf) (The section about the process stack applies to OS/X and Macho, not just Linux/ELF). – Michael Petch Jun 12 '16 at 00:54
  • 3
    If you want that at&t code to act the same you need to use a start symbol and tell gcc you want to bypass the _C_ runtime and define start as a new entry point. Otherwise you have to rewrite that at&t code to use the 64-bit calling convention also described in the document I linked to in my first comment. – Michael Petch Jun 12 '16 at 01:02
  • How would I do that? Thanks, I really appreciate it. – Addison Jun 12 '16 at 01:03
  • [This link](http://stackoverflow.com/questions/36861903/assembling-32-bit-binaries-on-a-64-bit-system-gnu-toolchain/36901649#36901649) from the [x86 tag wiki](http://stackoverflow.com/tags/x86/info) explains how to build executables with gcc from `.S` files that define `_start`, or ones that define `main`. (Use `-nostdlib` to not link in anything). – Peter Cordes Jun 12 '16 at 01:20
  • On OS/X you'd probably have to compile/assemble with GCC or AS and link separately. Something like this may work: `gcc -o add_att.o add_att.s -g -c` followed by `ld add_att.o -o add_att` . On Linux you can do it all from _GCC_ but GCC on OS/X is a bit peculiar in comparison. – Michael Petch Jun 12 '16 at 01:27
  • 1
    @PeterCordes : `-nostdlib` on OS/X with _GCC_ (which uses macho format and not elf) will not have the same effect. I assume you were hoping he'd be able to do something like `gcc -g add_att.s -o add_att -nostdlib` . On OS/X you'll have to compile/assemble the assembler separately and then link it (the longer way). If you were to use `-nostdlib` with GCC with will still expect to find a `_main` symbol and you can't override it with `-e` on OS/X as far as I know. You can do it with `-static -nostdlib` though – Michael Petch Jun 12 '16 at 01:43
  • Alternatively if you are going to build a static executable (which is generally not considered a desirable configuration in OSX) you could use `gcc -o add_att add_att.s -g -static -nostdlib` . This would bypass the _C_ runtime at process startup. – Michael Petch Jun 12 '16 at 01:54
  • @MichaelPetch: thanks, yeah I meant `gcc -o add_att add_att.s -g -static -nostdlib`. I guess I should update that answer I linked, if `-nostdlib` doesn't make static executables on OS X. I left it out for simplicity since my testing on Linux showed that it was redundant. – Peter Cordes Jun 12 '16 at 01:58
  • Thanks, I compiled it with `gcc -o add_att add_att.s -g -static -nostdlib` and that fixed the argc problem, but now argv isn't where I thought it should be... Any idea what's happening there? – Addison Jun 13 '16 at 14:40
  • That's really bad code because it doesn't follow the calling convention. – Benoît Jun 18 '16 at 16:34

0 Answers0