Author Topic: NASM on MacOS X  (Read 2927 times)

Serge

  • Guest
NASM on MacOS X
« on: April 22, 2009, 03:49:16 AM »
Hi,

I'm trying to jump start my ASM skills with NASM on my Mac. The problem that I ran into from the very beginning is linking C library to my ASM program. Actually I'm able to compile and link my "Hello World" successfully with the following:

nasm -f macho hello.s
gcc -o hello hello.o

But, when I try running this simple program:

extern _printf
global _main

section .data
   msg              db  "Hello, World!\n"

section .text

_main:
   push dword msg
   call _printf

push dword 0
   ret

I get segmentation fault. I'm probably doing something simple and stupid, but I can't figure out what. Please, help!

nobody

  • Guest
Re: NASM on MacOS X
« Reply #1 on: April 22, 2009, 05:00:58 AM »
Zero-terminate that string:

section .data
msg db "Hello, World!\n", 0

Nathan.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2373
  • Country: us
Re: NASM on MacOS X
« Reply #2 on: April 22, 2009, 07:15:22 AM »
That'll help. I think the main issue is not "cleaning up the stack" after the call to printf.

I don't know how far you've gotten in asm, Serge... The "call" instruction stores its return address on the stack. and the "ret" instruction expects to find it there. "_main" is called, so the stack looks like:

main's caller

Then we "push msg".

main's caller
msg

Then "call main" puts our local return address - the byte right after the call, push 0 now, but that's wrong - and the "ret" in printf takes it off. We never really "see" it. But the "msg" is still on the stack. The Windows API uses the "stdcall" calling convention, in which the called function *does* remove the parameters from the stack (the function ends in "ret 4" or "ret 8" or... "ret N" - number of bytes, not number of parameters). But we need to do it upon return - "add esp, 4". (more for more parameters) We could also pop a "junk" register "pop ecx" is common. Now the stack just has:

main's caller

on it, ready for the "ret". But you do a "push 0". That would be correct if you were ending with "call _exit" (which should also work - declare it "extern") - "_exit" expects an exitcode on the stack. But the usual convention is that the return value goes in eax. So "mov eax, 0" there, instead. (xor eax, eax is shorter... and more "asmish") You might want to try "mov eax, 42" or so. In Linux, we can see the exitcode of the last program with "echo $?" - dunno if it works on MacOS...

Getting back to your string... it should be zero-terminated. There's probably a zero there by chance, so it might work anyway, but isn't "right". Also, "\n" isn't going to work between regular quote marks, but it will if you use back-apostrophes - '`' (right under the tilde on my keyboard). A trick Nasm recently learned... the classic way was msg db "hello world", 10, 0.

A pitfall that awaits you... the calling convention requires that certain registers be preserved across called functions - that includes main. ebx, esi, edi, and ebp must be preserved. You don't change 'em, but if you do, in future code, put 'em back. Note that this means that calling C functions *will* trash ecx and edx behind your back!

Lessee, printf promotes all floats to double precision (8 bytes) . Functions that return float usually do so on the  top of the FPU stack.

... I may know more... I forget...

Good start getting it to compile and link without complaint!

Best,
Frank

Tom Timmermann

  • Guest
Re: NASM on MacOS X
« Reply #3 on: April 22, 2009, 05:43:08 PM »
Here is some code I use when on a Windows machine. I assume on a mac if would work the same ??

Here my _printf requires (2) pushes, the second for the format string and the first for the arg within the format string. Take a look at Paul Carters website for his tutorial and his code which has a lot more to say on this subject.

http://drpaulcarter.com/cs/


   ;print contents of eax
   mov eax,123456
   push eax
   push format
   call _printf
   ;dont forget to cleanup or Windows gives the crash dialog
   pop ecx
   pop ecx


   ;print some dots
   push '.'
   call _putchar
   pop ecx
   push '.'
   call _putchar
   pop ecx
   push '.'
   call _putchar
   pop ecx


   ;print newline
   push 0xa
   call _putchar
   pop ecx


   ;print a string
   push string1
   cld
   call _puts
   pop ecx
   ;make sure DF is clear (cld) before calling _puts !!!



ret


section .data
string1 db "Hello World !",0
format  db "%d",0
lfcr    db 0xa,0xd,0

TomT