Author Topic: linux/AMD64:call printf "Hello World" fails  (Read 23432 times)

nobody

  • Guest
linux/AMD64:call printf "Hello World" fails
« on: July 10, 2008, 04:10:00 AM »
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  global   main
  extern   printf

section   .text
main:

push msg
  call printf      ; printf(msg)
  pop rax
  ;add  esp, 4      ; remove the parameter 1*8

ret

msg: db 'Hello 32-bit world!',0xA,0x0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
successfully compiles and runs on a 32-bit VIA Nehemiah CPU (32bit slackware linux) using the commands
user@hn: 00 163> nasm -g -f elf a00_32.asm && gcc a00_32.o
user@hn: 00 164> ./a.out
Hello 32-bit world!
Exit 60

But when I go to my 64 bit AMD Athlon(tm) 64 X2 Dual Core Processor 4200+ (64bit Ubuntu 8.04, kernel 2.6.24-19-generic)
user@hn64:00$ nasm -g -f elf64 a00_32.asm && gcc -march=amd64 a00_32.o
user@hn64:00$ ./a.out
Illegal instruction
running gdb gives more info : Program received signal SIGILL, Illegal instruction.
0x00007f806e417d24 in printf_size () from /lib/libc.so.6

Both use
NASM version 2.03.01 compiled on Jul  6 2008

Is there any documentation on using the 64bit features that may help here? I am hoping to get a "Hello World" program running on my new 64 bit CPU so I can go back and modify some openGL code similarly. Since it also is scattered with many "call glFunctionX"s

Thanks in advance

nobody

  • Guest
Re: linux/AMD64:call printf "Hello World" fails
« Reply #1 on: July 10, 2008, 07:20:37 AM »
I've never run a 64-bit system, but I *think* even "just call printf" is different. First N parameters in regs, starting with edi(?) - N differs between Windows and Linux (portable much???) Seems I've heard of a "hidden parameter" in al, too(???). From "out here" it looks like a godawful mess! Maybe not so bad once you get used to it(?).

I'll post the only 64-bit example I've got - from Chuck Crayne (Thanks, Chuck!). I don't think it'll help you much with printf or openGL - uses sys_calls rather than libraries. Maybe *any* asm program will "warm the system up". :)

Really weird you're getting "illegal instruction", apparently from libc! I've seen a segfault in libc - caused by an invalid parameter. But SIGILL???

Courage! (and post if you learn anything, please!)

Best,
Frank

section .data
    string1 db  "Hello World!",10,0

section .text
    global _start

_start:
        ; calculate the length of string
        mov     rdi, string1
        mov     rcx, -1
        xor     al,al
        cld
        repnz scasb

; place the length of the string in RDX
        mov     rdx, -2
        sub     rdx, rcx

; print the string using write() system call
        mov     rsi, string1
        push    0x1
        pop     rax
        mov     rdi,rax
        syscall

; exit from the application here
        xor     rdi,rdi
        push    0x3c
        pop     rax
        syscall

nobody

  • Guest
Re: linux/AMD64:call printf "Hello World" fails
« Reply #2 on: July 11, 2008, 05:41:43 AM »
Thanks for the hint on using syscall.

I found some information which can be summarized as:

; function parameter (when linked with external libraries):
; r9   ; 6th param
; r8   ; 5th param
; rcx   ; 4th param
; rdx   ; 3rd param
; rsi   ; 2nd param
; rdi   ; 1st param
; call library

so the way I made a successful printf call was to not push the parameter onto the stack but rather set the rdi register ie
the working snippet of code equivalent to printf("Hello 64-bit world!\n")

msg: db 'Hello 64-bit world!',0xA,0x0
 ...
   mov   edi, msg
   call   printf

Success!

The curious thing was when I tried to extend this to more general library calls ie from openGL. Rather than using rdi, I had to use the xmm registers

half:     dd    0.5
neghalf:  dd   -0.5
...
   xorps   xmm2, xmm2
   movss   xmm1, [neghalf]
   movss   xmm0, [neghalf]
   call   glVertex3f            ; glVertex3f(-.5, -.5, 0);


p.s. If interested, the following is a complete working openGL version of Hello World running successfully on my amd64 with
"nasm -g -f elf64 hello_gl64.asm && gcc hello_gl64.o -lGL -lglut"
Note following is a modified version from 32bit example (http://www.cs.lmu.edu/~ray/notes/nasmexamples/) to work on my amd64.

global   main
        extern   printf
   extern   glClear
   extern   glBegin
   extern   glEnd
   extern   glColor3f
   extern   glVertex3f
   extern   glFlush
   extern   glutInit
   extern   glutInitDisplayMode
   extern   glutInitWindowPosition
   extern   glutInitWindowSize
   extern   glutCreateWindow
   extern   glutDisplayFunc
        extern   glutMainLoop

section   .text
msg: db 'Hello 64-bit world!',0xA,0x0
zero:     dd    0.0
one:     dd    1.0
half:     dd    0.5
neghalf:dd   -0.5

display:
   ;pseudo constructor to cleanly deal with local variables
        push rbp ; must save old ebp
        mov rbp, rsp ; point ebp to this frame

mov   edi, 16384
   call   glClear               ; glClear(GL_COLOR_BUFFER_BIT);

mov   edi, 9
   call   glBegin               ; glBegin(GL_POLYGON);

xorps   xmm2, xmm2
   xorps   xmm1, xmm1
   movss   xmm0, [one]
   call   glColor3f             ; glColor3f(1, 0, 0);

xorps   xmm2, xmm2
   movss   xmm1, [neghalf]
   movss   xmm0, [neghalf]
   call   glVertex3f            ; glVertex3f(-.5, -.5, 0);

xorps   xmm2, xmm2
   movss   xmm1, [one]
   xorps   xmm0, xmm0
   call   glColor3f             ; glColor3f(0, 1, 0);

xorps   xmm2, xmm2
   movss   xmm1, [neghalf]
   movss   xmm0, [half]
   call   glVertex3f            ; glVertex3f(.5, -.5, 0);

movss   xmm2, [one]
   xorps   xmm1, xmm1
   xorps   xmm0, xmm0
   call   glColor3f            ; glColor3f(0, 0, 1);

xorps   xmm2, xmm2
   movss   xmm1, [half]
   xorps   xmm0, xmm0
   call   glVertex3f           ; glVertex3f(0, .5, 0);

call   glEnd                ; glEnd();
        call   glFlush              ; glFlush();

mov   edi, msg
   call   printf

leave
   ret

main:
        ;pseudo init to cleanly deal with local variables
        push rbp ; must save old ebp
        mov   rbp, rsp ; point ebp to this frame
        sub   rsp, 16 ; make space for 4? locals

;mov   [rbp-4], edi
   ;mov   [rbp-16], rsi
   mov   rsi, [rbp-16]              ; argv
   lea   rdi, [rbp-4]               ; argc
        call   glutInit                   ; glutInit(&argc, argv)

mov   edi,0
   call   glutInitDisplayMode      ; glutInitDisplayMode(GLUT_RGB);
   mov   esi, 80
   mov   edi, 80
   call   glutInitWindowPosition   ; glutInitWindowPosition(80,80);
   mov   esi, 300
   mov   edi, 400
   call   glutInitWindowSize       ; glutInitWindowSize(400,300);
   mov   edi, msg
   call   glutCreateWindow         ; glutCreateWindow(msg);
   mov edi,   display
   call   glutDisplayFunc          ; glutDisplayFunc(display);
   call   glutMainLoop             ; glutMainLoop();

;pseudo cleanup for local variables helper
   mov   rsp, rbp       ; clean up locals
   pop   rbp          ; restore old ebp

;return success
   mov eax, 0
   ret