Archive

Archive for the ‘Assembler’ Category

x86 Linux assembler

August 2nd, 2009 Wesley 4 comments

The last few days I’ve been looking at x86 Linux assembler programming. I think it’s important to know how the code which you write in higher-level languages gets translated to low-level instructions and in what way things like libc or the kernel are involved. With some knowledge of assembler you can not only directly optimize some slower operations by implementing them in low-level assembly and by utilizing specific processor features, but in general you will also learn in which ways you can optimize your software by just writing the high-level code a little bit different – by anticipating how your code will translate into low-level assembler instructions.

That was my motivation for trying to do a few things with the Netwide Assembler (NASM). The result is a simple demo which utilizes libc, GLUT and OpenGL to display a rotating pyramid and cube.

ogl.asm

compiled ogl.asm application running in Ubuntu 8.04

The resulting code can be viewed here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
; OpenGL example in x86 Linux assembler / NASM using Glut
; Author: Wesley Stessens (wesley@ubuntu.com)
;
; OpenGL calls to create pyramid and cube are from Jeff Molofee's OpenGL tutorial
; See: http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=05
;
; Features:
;  - Calling C functions by cdecl conventions
;  - Using GLUT and OpenGL calls to perform 3D graphics
;  - Low-level framerate control
;
; Sample compile instructions:
; nasm -felf ogl.asm && ld -lglut -s -I/lib/ld-linux.so.2 -o ogl ogl.o
;
; This code is released as sample code in the public domain. Use it for whatever you want.
; Feel free to let me know if you found this code useful in any way.

; Glut
extern glutInit, glutInitDisplayMode, glutInitWindowSize, glutInitWindowPosition
extern glutCreateWindow, glutMainLoop
extern glutDisplayFunc, glutIdleFunc, glutReshapeFunc, glutKeyboardFunc
extern glutSwapBuffers

; Glu
extern gluPerspective

; OpenGL
extern glClearColor, glClearDepth, glDepthFunc, glEnable, glShadeModel
extern glClear, glLoadIdentity, glMatrixMode, glViewport
extern glTranslatef, glRotatef, glBegin, glEnd, glVertex3f, glColor3f

; Needed for framerate control
extern usleep

; Macros
%macro _3call 4
    push dword %4
    push dword %3
    push dword %2
    call %1
    add esp, 12
%endmacro
%macro _4call 5
    push dword %5
    push dword %4
    push dword %3
    push dword %2
    call %1
    add esp, 16
%endmacro

section .data
    title: db 'OpenGL in x86 Linux assembler / NASM using Glut', 0
    ; Data for FP math with 4 bytes
    n7: dd -7.0
    n6: dd -6.0
    n1p5: dd -1.5
    n1: dd -1.0
    p0p4: dd 0.4
    p0p5: dd 0.5
    p1: dd 1.0
    p1p5: dd 1.5
    p3: dd 3.0
    rottrm: dd 4.5
    rotsqm: dd -3.0

    ; Data for FP math with 8 bytes
    q0p1: dq 0.1
    q1: dq 1.0
    q45: dq 45.0
    q100: dq 100.0

    ; Data for framerate control
    mspf: dd 20000 ; ms per frame

section .bss
    ; Vars for rotation
    rottr: resd 1
    rotsq: resd 1
    ; Var for aspect ratio
    aspr: resq 1
    ; Vars for framerate control
    time: resd 2
    usecs: resd 1
    oldslp: resd 1

section .text
    global _start

fpsmanager:
    push eax
    push ebx
    push ecx
    push edx

    mov eax, 78 ; sys_gettimeofday
    mov ebx, time
    mov ecx, 0
    int 80h

    mov eax, [time + 4]
    sub eax, [usecs]
    mov ebx, [mspf]
    sub ebx, eax

    test eax, eax
    js keep_sleep
    test ebx, ebx
    js keep_sleep

    push ebx
    call usleep
    add esp, 4
    mov dword [oldslp], ebx
    jmp done_sleep

keep_sleep:
    push dword [oldslp]
    call usleep
    add esp, 4

done_sleep:
    mov eax, [time + 4]
    mov dword [usecs], eax

    pop edx
    pop ecx
    pop ebx
    pop eax
    ret

display:
    ; Prepare for drawing
    push dword 4100h ; GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT
    call glClear
    add esp, 4
    call glLoadIdentity

    ; Draw pyramid on the left of the screen
    _3call glTranslatef, [n1p5], 0, [n6]
    _4call glRotatef, [rottr], 0, [p1], 0
    push dword 9h ; GL_POLYGON
    call glBegin
    add esp, 4
    _3call glColor3f, [p1], 0, 0 ; Start drawing front face
    _3call glVertex3f, 0, [p1], 0
    _3call glColor3f, 0, [p1], 0
    _3call glVertex3f, [n1], [n1], [p1]
    _3call glColor3f, 0, 0, [p1]
    _3call glVertex3f, [p1], [n1], [p1]
    _3call glColor3f, [p1], 0, 0 ; Start drawing right face
    _3call glVertex3f, 0, [p1], 0
    _3call glColor3f, 0, 0, [p1]
    _3call glVertex3f, [p1], [n1], [p1]
    _3call glColor3f, 0, [p1], 0
    _3call glVertex3f, [p1], [n1], [n1]
    _3call glColor3f, [p1], 0, 0 ; Start drawing back face
    _3call glVertex3f, 0, [p1], 0
    _3call glColor3f, 0, [p1], 0
    _3call glVertex3f, [p1], [n1], [n1]
    _3call glColor3f, 0, 0, [p1]
    _3call glVertex3f, [n1], [n1], [n1]
    _3call glColor3f, [p1], 0, 0 ; Start drawing right face
    _3call glVertex3f, 0, [p1], 0
    _3call glColor3f, 0, 0, [p1]
    _3call glVertex3f, [n1], [n1], [n1]
    _3call glColor3f, 0, [p1], 0
    _3call glVertex3f, [n1], [n1], [p1]
    call glEnd

    ; Draw cube on the right of the screen
    call glLoadIdentity
    _3call glTranslatef, [p1p5], 0, [n7]
    _4call glRotatef, [rotsq], [p1], [p0p4], [p0p5]
    push dword 7h ; GL_QUADS
    call glBegin
    add esp, 4
    _3call glColor3f, 0, [p1], 0 ; Start drawing top face
    _3call glVertex3f, [p1], [p1], [n1]
    _3call glVertex3f, [n1], [p1], [n1]
    _3call glVertex3f, [n1], [p1], [p1]
    _3call glVertex3f, [p1], [p1], [p1]
    _3call glColor3f, [p1], [p0p5], 0 ; Start drawing bottom face
    _3call glVertex3f, [p1], [n1], [p1]
    _3call glVertex3f, [n1], [n1], [p1]
    _3call glVertex3f, [n1], [n1], [n1]
    _3call glVertex3f, [p1], [n1], [n1]
    _3call glColor3f, [p1], 0, 0 ; Start drawing front face
    _3call glVertex3f, [p1], [p1], [p1]
    _3call glVertex3f, [n1], [p1], [p1]
    _3call glVertex3f, [n1], [n1], [p1]
    _3call glVertex3f, [p1], [n1], [p1]
    _3call glColor3f, [p1], [p1], 0 ; Start drawing back face
    _3call glVertex3f, [p1], [n1], [n1]
    _3call glVertex3f, [n1], [n1], [n1]
    _3call glVertex3f, [n1], [p1], [n1]
    _3call glVertex3f, [p1], [p1], [n1]
    _3call glColor3f, 0, 0, [p1] ; Start drawing left face
    _3call glVertex3f, [n1], [p1], [p1]
    _3call glVertex3f, [n1], [p1], [n1]
    _3call glVertex3f, [n1], [n1], [n1]
    _3call glVertex3f, [n1], [n1], [p1]
    _3call glColor3f, [p1], 0, [p1] ; Start drawing right face
    _3call glVertex3f, [p1], [p1], [n1]
    _3call glVertex3f, [p1], [p1], [p1]
    _3call glVertex3f, [p1], [n1], [p1]
    _3call glVertex3f, [p1], [n1], [n1]
    call glEnd

    ; Update rotation
    fld dword [rottr]
    fadd dword [rottrm]
    fstp dword [rottr]
    fld dword [rotsq]
    fadd dword [rotsqm]
    fstp dword [rotsq]

    call glutSwapBuffers ; Swap buffers and display
    call fpsmanager ; Cap framerate if necessary
    ret

reshape:
    push ebp
    mov ebp, esp

    ; Prevent division by zero
    cmp dword [ebp+8], 0
    jne reshape_2
    inc dword [ebp+8]

reshape_2:
    fild dword [ebp+8]
    fidiv dword [ebp+12]
    fstp qword [aspr]

    push dword [ebp+12]
    push dword [ebp+8]
    push dword 0
    push dword 0
    call glViewport
    add esp, 16
    push dword 1701h; GL_PROJECTION
    call glMatrixMode
    add esp, 4
    call glLoadIdentity

    push dword [q100+4]
    push dword [q100]
    push dword [q0p1+4]
    push dword [q0p1]
    push dword [aspr+4]
    push dword [aspr]
    push dword [q45+4]
    push dword [q45]
    call gluPerspective
    add esp, 32

    push dword 1700h; GL_MODELVIEW
    call glMatrixMode
    add esp, 4

    pop ebp
    ret

keyhandler:
    ret

_start:
    ; Initialize glut
    push dword [esp+8]
    lea eax, [esp+8]
    push eax
    call glutInit
    add esp, 8
    push dword 1ah ; GLUT_RGBA|GLUT_DOUBLE|GLUT_ALPHA|GLUT_DEPTH
    call glutInitDisplayMode
    add esp, 4
    push dword 480
    push dword 640
    call glutInitWindowSize
    add esp, 8
    push dword 0
    push dword 0
    call glutInitWindowPosition
    add esp, 8

    ; Create window
    push title
    call glutCreateWindow
    add esp, 4

    ; Register functions
    push display
    call glutDisplayFunc
    call glutIdleFunc
    add esp, 4
    push reshape
    call glutReshapeFunc
    add esp, 4
    push keyhandler
    call glutKeyboardFunc
    add esp, 4

    ; Initialize OpenGL
    push dword 0
    push dword 0
    push dword 0
    push dword 0
    call glClearColor
    add esp, 16
    push dword [q1+4]
    push dword [q1]
    call glClearDepth
    add esp, 8
    push dword 203h; GL_LEQUAL
    call glDepthFunc
    add esp, 4
    push dword 0b71h; GL_DEPTH_TEST
    call glEnable
    add esp, 4
    push dword 1d01h; GL_SMOOTH
    call glShadeModel
    add esp, 4

    ; Frame rate cap initialization
    mov dword [oldslp], 0

    ; Enter main loop
    call glutMainLoop

    ; Exit (return with error code 0)
    mov eax, 1 ; sys_exit
    mov ebx, 0
    int 80h

I have also written two other smaller examples:
- marketing.asm is a really simple statistics application which calculates the ideal sample size given a few parameters
- alsawav.asm is a simple audio library which utilizes ALSA to play an unbuffered raw WAV/PCM sample

Please note that all these examples require an x86 Linux distribution. These examples will not work on any other operating system.

VN:F [1.6.3_896]
Rating: +3 (from 3 votes)

GBA programming in Linux

July 12th, 2007 Wesley 4 comments

GBA Rom

Mijn eerste GBA rom aan de linkerkant :) Nouja, afgekeken van een voorbeeldbestand…

Gisterenavond wou ik eens proberen om iets te programmeren voor mijn oude Game Boy Advance. Na wat rondgezocht te hebben bleek het niet eens zo moeilijk te zijn. Er is slechts weinig kennis nodig van ARM assembler. Programma’s kunnen gewoon in C/C++ worden geschreven en trage stukken nadien eventueel geoptimaliseerd met assembler.

Wel ga ik me moeten inwerken in het registersysteem van de Game Boy Advance.

Het was niet moeilijk om een cross compiler (compiler die uitvoerbare code genereert voor een ander platform dan hetgeen waarop de compiler draait) te compileren en gebruiken.

Mijn gecompileerd testproject werkte op emulators (zoals mednafen of visualboyadvance) maar het niet kon worden ingelezen door mijn EZF Advance client software! (software die ik gebruik om roms te uploaden naar een Flashkaart zodat ik de roms ook op mijn echte Game Boy Advance kan testen)
Screenshot van het probleem

Vandaag ben ik dus even bezig geweest met het uitzoeken van het probleem. De rom header moest gefixt worden en nog allerlei zaken. Ik had een perl script gevonden die alles voor me zou gefixt hebben, en de headers leken daarna inderdaad in orde, maar het programma wou nog steeds niet importeren in EZF Advance.

Toen vond ik devkitPro/devkitARM. Een heel pakket met alles wat ik nodig had. Heel veel GBA libs, voorbeelden, een cross compiler, header-fix-tool, etc.! Dus dat maar eens geïnstalleerd en een nieuw project gecompileerd op basis van één van de voorbeelden. En zie daar. Het draait nu ook op mijn Game Boy Advance (hardware)! Ik zou er een foto van hebben genomen, maar ik heb geen digitale camera :)

VN:F [1.6.3_896]
Rating: 0 (from 0 votes)
Categories: Assembler, C, C++, GBA, Hardware, Programming