0

I'm new to NASM and have struggle moving contents of variable from .data section to register. Following code outputs "Value: 0" instead of "Value: 1". If I write constant to register directly (mov qword rax, 25) everything works OK.

; /usr/local/bin/nasm -f macho64 sum.asm && ld -macosx_version_min 10.7.0 -lSystem -o sum sum.o && ./sum


section .data
myvar: dq 1234
message: db "Value: %i", 10, 0
.len:   equ     $ - message


global start

extern _printf
extern _exit

section .text
start:
    default rel

    ; This outputs "Value: 0"
    mov qword   [myvar], 1
    mov         rax, [myvar]

    ; This works:
    ; mov qword rax, 25


    ; Output
    mov rsi, rax                    


    mov qword   rax, 0                              
    lea         rdi, [rel message]
    call        _printf


    mov qword   rax, 0
    call        _exit

/usr/local/bin/nasm -v says: NASM version 2.11.08 compiled on Mar 10 2015

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Peter Prokop
  • 711
  • 1
  • 8
  • 19
  • style points: you can zero a 64bit register with `xor eax, eax`. Writing to a 32bit reg *always* clears the upper32 of the 64bit register. So `mov qword rax, 0` is probably loading `0` as an 8-byte immediate constant, rather than using an `xor` instruction that takes 2 bytes total to encode. Even `mov eax, 0` would be a lot better, but clearing registers with xor is the standard idiom. – Peter Cordes Sep 18 '15 at 01:01

2 Answers2

1

The OS X NASM 2.11.08 bug strikes again. Use an older version (like 2.11.06), or a newer version with a fix for relative symbol addressing in the data section. Or use yasm.


Like I said in comments, you can zero a 64bit register with xor eax, eax. That's the standard idiom.

Writing to a 32bit reg always clears the upper32 of the 64bit register. This saves a lot of instruction bytes compared to moving a 64bit immediate.

mov  qword rax, 25

Is still a 32bit immediate move. The qword is unnecessary. The instruction does have an unneeded REX prefix to make it a 64bit write, instead of just automatically clearing the high 32 by writing the low 32.

mov    eax, 25

does the same thing, but with fewer instruction bytes.

Community
  • 1
  • 1
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
0

Your code is correct, except for the global entry point main which is needed (but not required, you can adjust the entry point -- with link options). Here you are linking with the libc printf and exit functions. While compilers differ, using printf rather than _printf can help.

With only those semantic changes (and compiling on Linux instead of Mac), your code gives the desired output:

section .data
myvar: dq 1234
message: db "Value: %i", 10, 0
.len:   equ     $ - message

global main

extern printf
extern exit

section .text

main:
    default rel

    ; This outputs "Value: 0"
    mov qword   [myvar], 1
    mov         rax, [myvar]

    ; Output
    mov rsi, rax

    mov qword   rax, 0
    lea         rdi, [rel message]
    call        printf

    mov qword   rax, 0
    call        exit

Compile

$ nasm -felf64 -o obj/label64.o label64.asm
$ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib64/crt1.o \
/usr/lib64/crti.o  obj/label64.o /usr/lib64/crtn.o -lc -o bin/label64

Output

$ ./bin/label64
Value: 1

Note: you may need to adjust the paths needed by the link command. Otherwise, you can just call gcc and let it sort the paths out. E.g.:

$ gcc -o bin/label64 obj/label64.o
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • I think OS X does mangle names with underscores. ELF systems don't (http://stackoverflow.com/a/7827500/224132), but OS X uses the mach-o object file format. A quick google confirmed that OS X does mangle names this way: https://github.com/ldc-developers/ldc/issues/114 – Peter Cordes Sep 18 '15 at 01:10