7

When I use nasm -f macho64 asm1.asm I get the following error:

asm1.asm:14: error: Mach-O 64-bit format does not support 32-bit absolute addresses

This is asm1.asm

SECTION .data           ;initialized data

msg: db "Hello world, this is assembly", 10, 0

SECTION .text           ;asm code

extern printf
global _main

_main:
    push rbp
    mov rbp, rsp

    push msg
    call printf

    mov rsp, rbp
    pop rbp
    ret

I'm really new to assembly and barely know what these commands do. Any idea what's wrong here?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Daniel Node.js
  • 6,734
  • 9
  • 35
  • 57
  • @MichaelFoukarakis, but that answer does not really explain why `macho64` does not allow 32-bit absolute addressing. 32-bit absolute addressing works fine with elf64. – Z boson Oct 16 '14 at 11:03
  • @MichaelFoukarakis, I moved my answer to the http://stackoverflow.com/questions/13091987/x64-nasm-pushing-memory-addresses-onto-the-stack-call-function/13092703?noredirect=1#comment41463350_13092703. This question is now a duplicate. – Z boson Oct 16 '14 at 15:21

2 Answers2

6

Mac OS X, like other UNIX/POSIX systems, uses a different calling convention for 64-bit code. Instead of pushing all the arguments to the stack, it uses RDI, RSI, RDX, RCX, R8, and R9 for the first 6 arguments. So instead of using push msg, you'll need to use something like mov RDI, msg.

Drew McGowen
  • 11,471
  • 1
  • 31
  • 57
  • For reference, the related [section](https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/140-x86-64_Function_Calling_Conventions/x86_64.html) of Mac Dev Library, and the [updated ABI](http://x86-64.org/documentation/abi.pdf). – Michael Foukarakis Oct 16 '14 at 08:48
  • 1
    Could you provide an example of a working version of the original program for educational purposes! – akst Jul 27 '16 at 05:19
  • 2
    Or even better, **use `lea rdi, [rel msg]`** instead of a 10-byte `mov r64, imm64` with the 64-bit absolute address. RIP-relative LEA is smaller and more efficient, and is position-independent so it doesn't need a fixup if the OS wants to use ASLR on the executable. – Peter Cordes Mar 24 '18 at 10:40
-1

Besides what Drew McGowen points out, rax needs to be zeroed (no vector parameters).

But -f win64 or -f elf64 will work on this code. I suspect a bug in -f macho64 (but I'm not sure what macho64 is "supposed" to do). Until this gets fixed(?), the workaround is to use default rel or mov rdi, rel msg. I "think" that'll work for ya.

Frank Kotler
  • 3,079
  • 2
  • 14
  • 9
  • 2
    This is not a NASM bug, `push` does not support 64-bit immediate values, per the [documentation](http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf). – Michael Foukarakis Oct 16 '14 at 08:57
  • True enough, but why does Nasm think it's a 32-bit address? – Frank Kotler Oct 16 '14 at 09:43
  • It's not a bug, it just does not support 32-bit absolute addressing. The image base is large than 2^32 by default on OS X. See my answer. – Z boson Oct 16 '14 at 11:57
  • @MichaelFoukarakis, no it's not a bug in NASM, it's a limitation of OS X. On Linux it would be a 32-bit address because the image base is < 2^32 on Linux. – Z boson Oct 16 '14 at 12:01
  • 1
    `mov rdi, rel msg` is meaningless. The RIP-relative way to get a symbol address into a register is `lea rsi, [rel msg]`. `mov` is only available with a 32 or 64-bit immediate operand, not a `rel32`. If `mov` works, then it's because NASM decided to use a 64-bit absolute immediate, which you don't want; RIP-relative `lea` is smaller and more efficient. – Peter Cordes Mar 24 '18 at 10:37