Alweer geen Excel

Verder met TASM

Arnout van Kempen schrijft in deze rubriek over pret maken met computers. Hij gaat aan de slag met Pascal.

Tot nu toe keek ik naar registers en basisinstructies. Maar programmeren op een PC is méér dan de CPU; je praat ook met de machine zelf. Dat pad loopt historisch via BIOS en pas daarna via DOS.

BIOS vóór DOS waarom dit zo briljant is (CP/M-erfenis) 
In de CP/M-wereld werd het besturingssysteem bewust in lagen gesplitst:

  • CCP (shell), BDOS (OS-diensten) en BIOS (hardwarelaag).
  • Die BIOS-laag bevat alle machine-specifieke code. Port je naar een andere computer, dan herschrijf je alleen het BIOS; de rest blijft werken.

IBM neemt dit idee over: op de PC zet IBM de BIOS in ROM

  • Dat levert een stabiele, uniforme interface dicht op de hardware (scherm, keyboard, disk).
  • Software (DOS, applicaties) kan op elke IBM-compatibele machine draaien, zolang het BIOS dezelfde "contracten" nakomt.

En daar begint de clone war: wie een functioneel equivalent van IBMs BIOS levert (Phoenix doet dat schoon-kamer), kan MS-DOS en DOS-software draaien op niet-IBM-hardware. BIOS ≠ DOS: het is firmware van de fabrikant; DOS is vervangbare software erbóven.

Waar DOS in het plaatje past
DOS wordt vanaf disk geladen:

  • IO.SYS (basisdrivers/bootstrap)
  • MSDOS.SYS (de kernel: OS-diensten)
  • COMMAND.COM (de shell; vervangbaar door bijvoorbeeld 4DOS)

Programma's praten met DOS via INT 21h (de DOS-API). DOS zelf schakelt waar nodig door naar BIOS-INT's om hardware te bedienen. Kort: BIOS = ijzerlaag; DOS = OS-diensten en files; shell = vervangbaar programma.

Interrupts: wat en hoe (zonder meteen te "doen")
Een software-interrupt (INT n) is een sprong naar een vector in de Interrupt Vector Table (IVT) op 0000:0000. Mechaniek:

  • CPU pusht FLAGS, CS, IP; zet interrupts uit (IF=0); springt naar handler van n.
  • IRET zet IP, CS, FLAGS terug: je komt exact terug waar je was.

Hardware-interrupts doen hetzelfde, maar worden door devices getriggerd (via de PIC). Voor dit deel volstaat: we roepen DOS met INT 21h, BIOS met bijv. INT 10h/16h/13h.

INT 21h (DOS-API) in een notendop
Je zet het functienummer in AH, parameters in andere registers. Drie nuttige starters:

  • AH=09h print $-terminated string, DS:DX wijst naar de string
  • AH=01h lees één toets, ASCII in AL
  • AH=4Ch beëindig programma, exitcode in AL

BIOS-INTs (voor het idee)

  • INT 10h video (tekstkleur, cursor, modus)
  • INT 16h keyboard (toets ophalen)
  • INT 13h disk (sector I/O)

Zo zie je de scheidslijn: BIOS = device-nabij; DOS = files, processen, algemene diensten.

SI/DI en veilig kopiëren: een compleet voorbeeld
We laten zien hoe je een string kopieert met REP MOVSB en vervolgens print via DOS. De kern: lengte correct bepalen en voldoende doelruimte reserveren.

ORG 100h

START:

    ; 1) Kopieer SRC DEST (exact LEN bytes)
    mov si,OFFSET SRC
          mov di,OFFSET DEST
    mov cx,LEN
          rep movsb 

    ; 2) Print DEST via DOS (AH=09h verwacht $-terminated DS:DX)
    mov dx,OFFSET DEST
    mov ah,9
    int 21h

    ; 3) Exit
    mov ax,4C00h
    int 21h 

; ----- Data -----

SRC  db 'Assembler is leuk!$'
LEN  equ $-SRC                ; assemble-time: lengte in bytes van SRC
                              ; ($ is de huidige locatie; $-SRC = afstand, dus aantal bytes.
                              ; In dit voorbeeld inclusief de '$'-terminator → precies goed
                              ; voor functie 09h en precies het aantal te kopiëren bytes.)
DEST db LEN dup(?)            ; reserveer exact evenveel ruimte voor de kopie
                              ; (vraagteken = oningevuld; we schrijven er zo in)

END START

Waarom LEN  equ $-SRC essentieel is

  • $ is de location counter van de assembler (niet van je programma tijdens runtime).
  • $-SRC is een assemble-time berekening: het verschil tussen "nu" en het adres van SRC. Dat is exact het aantal bytes van de gedefinieerde data tot "nu" — hier dus de volledige string inclusief $.
  • Met EQU maak je van die berekende waarde een constante. Dat getal wordt in de code geplaatst:
  • in CX (zoveel bytes kopiëren)
  • én in de declaratie van DEST (zoveel bytes reserveren).

Zonder voldoende gereserveerde doelruimte (DEST db LEN dup(?)) overschrijf je geheugen. In DOS is er geen bescherming: één fout en je slingert over je eigen data of zelfs DOS heen. Juist daarom is assemble-time lengteberekening zon krachtige (en veilige) gewoonte.

Korte epiloog (orde in de concepten)

  • BIOS ≠ DOS: BIOS hoort bij de hardware (ROM), DOS is vervangbare software (IO.SYS + MSDOS.SYS + shell).
  • Interrupts zijn de standaard interface: INT 21h voor DOS, INT 10h/16h/13h voor BIOS.
  • Assembler-praktijk: correcte lengte en bufferreservering zijn net zo belangrijk als het juiste register.

Volgende keer ga ik met TASM de structuur verdiepen: CALL/RET, stackframes met BP, registers en flags netjes saven/restoren (PUSHF/POPF). En we bouwen een iets grotere routine met lussen en condities. Daarna heb je alles in handen om betrouwbare (en leesbare) ASM-utilities te schrijven en om ze later netjes te koppelen aan Pascal.

Arnout van Kempen is naast computernerd ook directeur compliance & risk bij aaff. Hij schrijft op persoonlijke titel.

Gerelateerd

reacties

Reageer op dit artikel

Spelregels debat

    Aanmelden nieuwsbrief

    Ontvang elke werkdag (maandag t/m vrijdag) de laatste nieuwsberichten, opinies en artikelen in uw mailbox.

    Bent u NBA-lid? Dan kunt u zich ook aanmelden via uw ledenprofiel op MijnNBA.nl.