-2

I want to call printf function from assembly language in linux.

i want to know the method for for 64 bit and 32 bit assembly language programs.

1) please tell me for two cases if i want to pass a 32 bit arguement and 64 bit arguement in printf with a string. how should i do it?

2) for x86 32 bit architecture if i want to do the same thing as in point 1.

please tell me the code. and let me know do i need to adjust the stack for both cases and do i just need to pass the arguements in registers?

Thanks alot

user2277648
  • 121
  • 2
  • 7
  • i am using corei7 64 bit architecture. but i want to know the method for calling printf in both 32 bit and 64 bit programs. I want to know where to pass the arguements and whether it is required to adjust the stack manually after the call. please give me example for both cases. for passing 32bit and 64 bit arguements with string in both cases. – user2277648 Nov 07 '16 at 06:16
  • 1
    The very first hit when googling _"printf nasm"_ or _"x86-64 printf nasm"_ is a page with a bunch of example programs, including one that calls `printf`. – Michael Nov 07 '16 at 10:12

1 Answers1

3

There are 2 ways to print a string with assembly language in Linux.

1) Use syscall for x64, or int 0x80 for x86. It's not printf, it's kernel routines. You can find more here (x86) and here (x64).

2) Use printf from glibc. I assume you are familiar with the structure of NASM program, so here is a nice x86 example from acm.mipt.ru:

global main

;Declare used libc functions
extern exit
extern puts
extern scanf
extern printf

section .text

main:

;Arguments are passed in reversed order via stack (for x86)
;For x64 first six arguments are passed in straight order
;  via RDI, RSI, RDX, RCX, R8, R9 and other are passed via stack
;The result comes back in EAX/RAX
push dword msg
call puts
;After passing arguments via stack, you have to clear it to
;  prevent segfault with add esp, 4 * (number of arguments) 
add esp, 4

push dword a
push dword b
push dword msg1
call scanf
add esp, 12
;For x64 this scanf call will look like:
;  mov rdi, msg1
;  mov rsi, b
;  mov rdx, a
;  call scanf

mov eax, dword [a]
add eax, dword [b]
push eax
push dword msg2
call printf
add esp, 8

push dword 0
call exit
add esp, 4
ret

section .data
msg  : db "An example of interfacing with GLIBC.",0xA,0
msg1 : db "%d%d",0
msg2 : db "%d", 0xA, 0

section .bss
a resd 1
b resd 1

You can assembly it with nasm -f elf32 -o foo.o foo.asm and link with gcc -m32 -o foo foo.o for x86. For x64 just replace elf32 with elf64 and -m32 with -m64. Note than you need gcc-multilib to build x86 programs on x64 system using gcc.

trexxet
  • 176
  • 3
  • 14
  • 1
    You actually need `gcc -nostartfiles` to link a `.o` that defines `_start` (instead of `main`). See http://stackoverflow.com/questions/36861903/assembling-32-bit-binaries-on-a-64-bit-system-gnu-toolchain/36901649#36901649 for the full details. – Peter Cordes Nov 07 '16 at 17:03
  • 1
    Also, after a CALL, you need to add, not sub. `sub esp, 12` reserves even more stack space. Or leave ESP alone and store into the space you didn't pop with MOV instructions, to set up for the next CALL. – Peter Cordes Nov 07 '16 at 17:04
  • `exit()` is guaranteed not to return; it can't fail. So you don't need to pop the arg and `ret` after it. Or you can just return 0 from `main` in the first place, which does the same thing. I was amused to see you added a `add esp, 4` after the `call exit` :P – Peter Cordes Nov 07 '16 at 21:14