1

I am new to assembly language programing, and here I am trying to call C standard library function puts from my assembly code, but I am continuously getting segmentaion fault. Please help; Operating system : LINUX 16.04 Assembler : nasm Machine : intel x86 - 64bit

;comiple and build:
;                   nasm -f elf64 -F stabs helloc.asm
;                   gcc -o helloC helloC.o
[SECTION .data]
   msg: db "Hello C",0
[SECTION .bss]

[SECTION .text] 
 extern puts

 global main 
 main:
  push rsp

  push dword msg
  call puts
  add rsp,4

  pop rsp
  ret
Jester
  • 56,577
  • 4
  • 81
  • 125
snehm
  • 223
  • 3
  • 13
  • 4
    The [64 bit calling convention](https://en.wikipedia.org/wiki/X86_calling_conventions#System_V_AMD64_ABI) is different. TL;DR: `push rbp; mov rdi, msg; call puts; pop rbp; ret`. – Jester Dec 22 '17 at 15:46
  • Thank you. How to compile, link and run 32-bit instruction set on 64 bit machine? if it is possible. – snehm Dec 22 '17 at 16:05
  • 2
    `nasm -f elf32` + `gcc -m32` – Jester Dec 22 '17 at 16:05
  • gcc -m32 gives error "cannot find -lgcc, cannot find -lgcc_s, cannot find -lc ld returned 1 exit status". I had generated obect code for my assembly using nasm -g -f elf32 -F stabs helloC.asm. Do I need to install any aditional library? – snehm Dec 22 '17 at 16:27
  • 3
    Yes, `gcc-multilib` package usually. – Jester Dec 22 '17 at 16:27
  • Thank very much. It worked, finally! – snehm Dec 22 '17 at 16:36
  • 1
    https://stackoverflow.com/questions/36861903/assembling-32-bit-binaries-on-a-64-bit-system-gnu-toolchain – Peter Cordes Dec 22 '17 at 17:02
  • 3
    push/pop RSP is not what you want. push/pop ESP isn't what you want either, in 32-bit code. – Peter Cordes Dec 22 '17 at 17:03
  • 2
    Try to toy around first with *working* examples? So you can see when your change does break it. Starting from scratch you can produce several mistakes at the same time, sometimes even cancelling each other, so the code will output what you expected while having serious problems inside. And that's another thing, don't judge correctness of assembly code by it's output only, but use debugger to step over single instructions and reason about each of them, if it really works as you intended and all side effects are wanted/needed. – Ped7g Dec 22 '17 at 17:08

1 Answers1

1

to explain Comments More, start with x86 calling convention and your code.

x86 Calling Convention

In x86, arguments are located in stack. So basically your function call is x86 way. for example, If you build your code for x86,

[SECTION .data]
   msg: db "Hello C",0
[SECTION .bss]

[SECTION .text] 
 extern puts

 global main 
 main:
  push ebp
  mov ebp, esp
  and esp, 0xfffffff0
  sub esp, 0x10

  mov DWORD PTR [esp], msg
  call puts


  mov esp, ebp
  pop ebp
  ret

It may works fine.

x86-64 Calling Convention

Main difference is two things.

  • using 8 bytes to represent address, of course
  • use 6 registeres (rdi, rsi, rdx, rcx, r8, r9) for represent first 6 arguments (rest is located in stack)

so first, you should change push dword msg to mov rdi, msg, and don't clean stack after call (because you didn't push anything to stack)

after change:

[SECTION .data]
   msg: db "Hello C",0
[SECTION .bss]

[SECTION .text] 
 extern puts

 global main 
 main:
  push rbp
  mov rbp, rsp
  and rsp, 0xfffffffffffffff0

  mov rdi, msg
  call puts


  mov rsp, rbp
  pop rbp
  ret

EDIT: from System V ABI, for call instruction stack be should 16-byte aligned. so push rbp has effect to alignment, but it is not correct purpose to use. to change that, make stack save logic for both x86 and x86-64.

j31d0
  • 141
  • 5
  • You might be surprised but `push/pop` here isn't useless. The x86-64 System V ABI has a requirement (for about a decade I think) that the stack be 16 byte (or 32 byte aligned) at the point just before a call is made. The stack is aligned before the call to main by the C Runtime. It is misaligned by 8 when the return address is pushed. Pushing a register will re-align to a 16-byte boundary again and that may be required for the call to `puts` – Michael Petch Jan 03 '18 at 03:10
  • I didn't know that! Thanks for advice. but Is it mandatory to execute?? I never aligned stack for call function (except some system calls which needs), but I haven't seen segmentation fault or some errors.. – j31d0 Jan 03 '18 at 03:15
  • 1
    You can't rely on not doing it. `puts` may not use any instructions that require 16-byte aligned instructions but nothing prevents the C library developers from using such instructions. So you should assume 16 byte alignment is necessary for anything that is x86-64 System V ABI compliant. – Michael Petch Jan 03 '18 at 03:17
  • 2
    You may be able to see things fail if you use `printf` that has a format specifier that prints a floating point value. – Michael Petch Jan 03 '18 at 03:18
  • 1
    [The current version of the i386 System V ABI](https://stackoverflow.com/questions/18133812/where-is-the-x86-64-system-v-abi-documented) (used on Linux) also requires 16-byte alignment. 16-byte used to be only a de-facto standard (maintained by gcc's default of `-mpreferred-stack-boundary`), but maybe years ago it became official so 32-bit code can efficiently use SSE2 load / store to the stack. (I think the x86-64 ABI has required 16-byte alignment from the start, back in 2000 before the first AMD64 silicon was released.) – Peter Cordes Jan 03 '18 at 03:40