Als je ooit diep in de wereld van systemen programmeren bent gedoken ben je vast Assembly Language tegen gekomen. Assembly klinkt misschien intimiderend, maar geloof me, het is eigenlijk heel toegankelijk. In dit artikel gaan we een systeem assembleren en linken op een x86_64 Linux systeem.
Inhoudsopgave
Concepten
Wat is assembling?
Assembly Language is een laag-niveau programmeertaal dat heel dicht tegen de instructieset van de processor aan zit. Elk stukje assembly code komt direct overeen met een specifieke binaire machine-instructie. Het proces waar assembly wordt getransformeerd naar binaire machine-instructie (machinecode) noemen we assembling.
Hoe verschilt assembling van compiling?
Als assembling het omzetten van code naar machine instructies is, wat maakt het dan anders dan compiling?
Het grote verschil zit in het niveau van de taal waarmee er wordt gewerkt. Assembly language is een low-level taal die het dichtst bij machine-instructies ligt, hierdoor is de vertaalslag van Assembly naar machinecode vrij eenvoudig. Bij het assembleren hoeft er alleen een directe vertaling gemaakt te worden.
Compiling verwijst naar het vertalen van high-level talen, bijvoorbeeld C, deze talen zijn veel abstracter en gebruiksvriendelijker dan assembly. Hierdoor moet er tijdens het vertalen van de taal rekening gehouden worden met dingen als: optimalisatie, geheugenbeheer en foutdetectie afhandelen.
Wat is Linking
Linking is de stap die volgt nadat je code geassembleerd of gecompileerd is naar objectbestanden. Het is de fase waarin al die losse stukjes code bij elkaar worden gebracht om uiteindelijk een uitvoerbaar programma te vormen.
Wanneer je programmeert, schrijf je meestal code verspreid over meerdere bestanden. Elk van deze bestanden wordt afzonderlijk gecompileerd of geassembleerd naar objectbestanden. Deze objectbestanden bevatten niet alleen de machinecode die jouw instructies vertegenwoordigt, maar ook symbolen die nodig zijn om de verschillende delen van je code met elkaar te verbinden.
Assembling Hello World
De volgende assembly code schrijft “Hello, World!” naar de standard output op Linux.
section .data
message db "Hello, World!", 0xa
message_len equ $ - message
section .text
global _start
_start:
mov eax, 4
mov ebx, 1
mov ecx, message
mov edx, message_len
int 0x80
jmp _exit
_exit:
mov eax, 1
xor ebx, ebx
int 0x80
De volgende code sample laat zien hoe je de assembly code kan assemblen, linken en uitvoeren.
#!/bin/bash
# Assemble main.asm met nasm en genereer main.o
# voor 64-bit Linux
#
nasm -f elf64 main.asm -o main.o
# Linken van main.o met ld om een
# executable te genereren
#
ld main.o -o main
# Uitvoeren van de executable
#
./main
Conclusie
Het proces om assembly code om te zetten naar een uitvoerbaar bestand is eenvoudig in vergelijking met de complexiteit van de omgeving waarvoor deze code wordt geschreven en gebruikt. Effectief ontwikkelen met Assembly vereist een diep begrip van de onderliggende hardware en de nuances van de machine-instructies.