Works by accident (you still forgot to initialize projection matrix, for example). Here's your code with some notes.
;-------------------------------------------------------------------------------------
; triangle.asm
;
; Simple triangle using opengl and freeglut
;
; To assemble:
; nasm -felf64 -Wall triangle.asm -o triangle.o
; To link:
; gcc -m64 -Wall -Wextra triangle.o -lGL -lglut -o triangle
; To run:
; ./triangle
;-------------------------------------------------------------------------------------
; Note that the parameter -m64 may not suit all architectures (see -m in man gcc)
; Nasm supports elf format position-independent code (PIC) features. To call an
; external routine (library function) simply append " wrt ..plt" to the call,
; for example call glClear wrt ..plt
; (Nasm manual section 9.2)
;-------------------------------------------------------------------------------------
; Fred's notes:
;
; See FIXME notes on the code.
; Also, using -march=native and -O3 for linking is superfluous.
; If you are using gcc for x86-64, -m64 is also superfluous.
; Another one: GCC and LD documentation for -l options says it is prudent to use them
; at the END of the command, like:
;
; gcc triangle.o -o triangle -lGL -lglut
;
; Use -s options if you don't want symbolic data on your executable.
;-------------------------------------------------------------------------------------
; FIXME: Not an error, but to make sure we are dealing with x86-64 here, use
; "bits 64" directive.
default rel
global main
extern glutInit
extern glutInitDisplayMode
extern glutInitWindowSize
extern glutInitWindowPosition
extern glutCreateWindow
extern glutDisplayFunc
extern glutMainLoop
extern glClearColor
extern glClear
extern glColor3f
extern glOrtho
extern glBegin
extern glVertex3f
extern glEnd
extern glFlush
;----------------------------------------------------
; FIXME: Not an error, but since you won't change any of these values,
; it is practical to alocate them in .rodata section, instead of .data.
section .rodata
dq_minusone dq -1.0
dq_one dq 1.0
dd_pointfour dd 0.4
dd_one dd 1.0
dd_minuspointseven dd -0.7
dd_pluspointseven dd 0.7
dd_minusone dd -1.0
wintitle db "Triangle",0
; FIX: winhandle moved to .bss section because we don't need this on the executable image.
section .bss
winhandle resq 1
;----------------------------------------------------
section .text
drawtriangle:
push rbp
push rbx
; FIXME: sub rsp,8 is shorter
lea rsp,[rsp-8]
; FIXME you only need to do this ONCE.
movd xmm0, dword [dd_pointfour]
movd xmm1, dword [dd_pointfour]
movd xmm2, dword [dd_pointfour]
movd xmm3, dword [dd_pointfour]
call glClearColor wrt ..plt
; FIXME: No need to assign value to RDI, EDI will suffice.
; Assigning to EDI will zero upper 32 bits automatically
; and create a shorter instruction encoding.
mov rdi, 16384
call glClear wrt ..plt
; FIXME: This should be inside glBegin/glEnd block.
movd xmm0, dword [dd_one]
movd xmm1, dword [dd_one]
movd xmm2, dword [dd_one]
call glColor3f wrt ..plt
; FIXME: This should be done only ONCE.
; And the projection matrix should be initialized ONCE too.
movq xmm0, qword [dq_minusone]
movq xmm1, qword [dq_one]
movq xmm2, qword [dq_minusone]
movq xmm3, qword [dq_one]
movq xmm4, qword [dq_minusone]
movq xmm5, qword [dq_one]
call glOrtho wrt ..plt
; FIXME: No need to assign value to RDI, EDI will suffice.
; Assigning to EDI will zero upper 32 bits automatically
; and create a shorter instruction encoding.
mov rdi, 4
call glBegin wrt ..plt
; FIXME: No need to zero all YMM registers! pxor xmm2,xmm2 will suffice (and it is faster).
vzeroall
movd xmm0, dword [dd_minuspointseven]
movd xmm1, dword [dd_pluspointseven]
; last parameter already zero, pxor xmm2, xmm2
; FIXME: Argumentos already set, but they could be changed by the called function!
call glVertex3f wrt ..plt
movd xmm0, dword [dd_pluspointseven]
; parameter already set, movd xmm1, dword [dd_pluspointseven]
; last parameter already zero, pxor xmm2, xmm2
; FIXME: Argumentos already set, but they could be changed by the called function!
call glVertex3f wrt ..plt
pxor xmm0, xmm0
movd xmm1, dword [dd_minusone]
; last parameter already zero, pxor xmm2, xmm2
; FIXME: Argumentos already set, but they could be changed by the called function!
call glVertex3f wrt ..plt
call glEnd wrt ..plt
call glFlush wrt ..plt
; FIXME: add rsp,8 is shorter.
lea rsp,[rsp+8]
pop rbx
pop rbp
ret
main:
; FIXME: sub rsp,8 is shorter.
lea rsp, [rsp-8]
mov [rsp], edi
lea rdi, [rsp]
call glutInit wrt ..plt
; FIXME: No need to assign value to RDI, EDI will suffice.
; Assigning to EDI will zero upper 32 bits automatically
; and create a shorter instruction encoding.
xor rdi, rdi
call glutInitDisplayMode wrt ..plt
; FIXME: No need to assign value to RDI and RSI, EDI and ESI will suffice.
; Assigning to EDI and ESI will zero upper 32 bits automatically
; and create a shorter instruction encoding.
mov rdi, 500
mov rsi, 500
call glutInitWindowSize wrt ..plt
; FIXME: No need to assign value to RDI and RSI, EDI and ESI will suffice.
; Assigning to EDI and ESI will zero upper 32 bits automatically
; and create a shorter instruction encoding.
mov rdi, 100
mov rsi, 100
call glutInitWindowPosition wrt ..plt
mov rdi, wintitle
call glutCreateWindow wrt ..plt
; FIXME: glutCreateWindow will return in 'int' (DWORD).
; So you need to store only EAX. But, since you aren't
; using this handle for nothing, no storage is necessary.
mov [winhandle], rax
mov rdi, drawtriangle
call glutDisplayFunc wrt ..plt
call glutMainLoop wrt ..plt
; FIXME: No need to assign value to RAX, EAX will suffice.
; Assigning to EAX will zero upper 32 bits automatically
; and create a shorter instruction encoding.
xor rax, rax ; return 0 to OS
; FIXME: add rsp,8 will be shorter.
lea rsp,[rsp+8]
; FIX: You forgot this!
ret