6

i try write simple assemble program with printf function. I compile it nasm -f elf 64 and link using gcc. After run i see segmentation fault. What is wrong?

[Bits 32]

extern printf
global main

section .data 

hello:
db "Hello", 0xa, 0 

section .text

main:

push hello
call [printf]

add esp, 4

mov eax, 1
mov ebx, 0
int 80h
user902691
  • 1,149
  • 4
  • 20
  • 46
  • 2
    Why do you want to assemble a program that's clearly 32-bit to `elf64`? – Daniel Kamil Kozar Aug 02 '12 at 20:50
  • Because when I won't do this I see: `/usr/bin/ld: i386 architecture of input file ./asemlebr.o is incompatible with i386:x86-64 output` – user902691 Aug 02 '12 at 20:59
  • 1
    Where have you written `printf`? If you're thinking about calling the one in the C library, it's going to take a lot more work than that - you'll need to make sure that the library's initialization code is called, set up your stack frame and arguments according to the ABI for the platform you're on, and link your program with the library, at the very least... – twalberg Aug 02 '12 at 21:19
  • @twalberg: Actually this will work fine. The OP is writing `main`, so CRT startup code will init glibc before calling main even in a static executable. It would also be safe from `_start` in a *dynamically* linked binary with glibc, because glibc's init functions are called by the dynamic linker using the same mechanism that runs static initializers in C++ library code. Related: https://stackoverflow.com/questions/36861903/assembling-32-bit-binaries-on-a-64-bit-system-gnu-toolchain for more about static vs. dynamic binaries and linking libc or not. – Peter Cordes Oct 25 '17 at 09:34
  • The main danger here is that `sys_exit` won't flush stdout, but it will be full-buffered if it's not a TTY. – Peter Cordes Oct 25 '17 at 09:35

2 Answers2

8

Linux on ia32 doesn't use the same calling convention as on amd64. As your code uses the former you must assemble it as 32 bits and link with a 32 bits libc. On debian you'll need the libc6-dev-i386 package.

You must also replace 'call [printf]' with 'call printf', that's a mistake.

Note also that as you are using the main interface you should return from main instead of performing an exit system call to allow the C runtime shutdown code to run.

Hello World example for x86-32 with build instructions.

If you are working on amd64, you might want to learn how to write 64 bits assembly instead.

Hello World example for x86-64 with build instructions.

3

If you really want to get a 32 bit binary as your code header shows then you just need to fix the line:

call [printf]

changing it to:

call printf

When you do call [printf] you are not calling printf but the address pointed by first printf code bytes, that construction ([address]) is called an effective address.

olivecoder
  • 2,858
  • 23
  • 22