Statistics

Members: 1927
News: 293
Web Links: 1
Visitors: 3926790

Who's Online

We have 2 guests online
Damn Vulnerable LinuxDamn Vulnerable Linux (DVL) is a Linux-based (modified Damn Small Linux) tool for IT-Security & IT-Anti- Security and Attack & Defense. [CLICK HERE FOR MORE INFOS! ]

Featured Conference Video

T16-Recon2006-Joe_Stewart-OllyBonE.gif OllyBone - Semi-Automatic Unpacking on IA-32. View the conference video here!
Home arrow Articles - Black Hat Methods arrow Assembly arrow Inline Assembler With Modula
Inline Assembler With Modula
User Rating: / 1
PoorBest 
Written by Jan Verhoeven   


I don't want to start a compiler-war in the assembler programmer's journal, but I do want to show some nice in-line assembly routines for FST Modula-2. FST (or Fitted Software Tools) was a shareware Modula-2 compile made by Roger Carvalho. He eventualy gave up the concept of shareware and made his final version freeware. If you look carefully you can find this package in many software repositories like Simtel. Also the FreeDOS website used to harbor this final version.

 

 

For this Modula-2 compiler I used my VGA routines (see previous issues) and some in-line assembly to give this compiler a way to do graphics modes.

I uploaded the full sources to SimTel some months (or years?) ago, so if you would like to have a detailed look at it, go there and look for it.

Modula-2 is despised by many, but it is the most structured language ever made. And that's also probably the reason why most coders refuse to use it. You must follow the compiler, whatever you do. A high price, but the result is that Modula-2 programs seldomly crash. They can bail-out in the middle of the program, but they will not hang due to a pointer or indexing error.

Anyway, here's my addition to this marvelous language:


IMPLEMENTATION MODULE VgaLib;

PROCEDURE SHL (x, y : CARDINAL) : CARDINAL; (* Shift left x, y bits. *)

VAR result : CARDINAL;

BEGIN

ASM

        MOV  AX, x
MOV  CX, y
AND  CX, 15         (* Mask off lower nybble    *)
JCXZ ok             (* Get out if no shift.     *)
SHL  AX, CL
ok: MOV  result, AX     (* Store result.    *)

END;
RETURN result;
END SHL;


The only "drawback" is that the in-line code must be 8088 style. So you won't be eable to use MMX instructions, but almost no-one ever needs those.

FST Modula-2 offers direct access to (values of) variables. Neat. Makes the in-line feature very convenient to use.


PROCEDURE SetColour (Colour : CHAR); (* Define colour to work with. *)

BEGIN

ASM

        MOV  DX, 03C4H          (* VGA controller port  *)
MOV  AH, Colour
MOV  AL, 2
OUT  DX, AX

END;
END SetColour;


Compare the following routine with the one I entered for the VGA-12h code in A86 assembly language format. There's some Modula-2 overhead, but the actual plotting is done in ASM, for speed-reasons.


PROCEDURE Plot (VAR InWin : WinData); (* Plot point on CurX, CurY. *)

VAR x, y : CARDINAL;

BEGIN

x := InWin.CurX + InWin.TopX;
y := InWin.CurY + InWin.TopY;

ASM

        MOV  AX, 0A000H
MOV  ES, AX         (* Set up segment register *)
MOV  CX, x
AND  CX, 7          (* Which bit to plot? *)
MOV  AH, 80H
SHR  AH, CL         (* Compose plotting mask *)
MOV  AL, 8
MOV  DX, 03CEH
OUT  DX, AX         (* Set plottingmask *)
MOV  AX, y          (* Calculate offset in Video RAM *)
MOV  BX, AX
ADD  AX, AX
ADD  AX, AX
ADD  AX, BX         (* AX := 5 * Y *)
MOV  CL, 4
SHL  AX, CL         (* AX := 16 * 5 * Y *)
MOV  BX, x
SHR  BX, 1
SHR  BX, 1
SHR  BX, 1
ADD  BX, AX         (* plus X / 8 *)
MOV  AL, ES:[BX]
MOV  AL, 0FFH
MOV  ES:[BX], AL    (* and plot it *)

END;
END Plot;

PROCEDURE DrawH (VAR InWin : WinData; Flag : BOOLEAN);

(* Draw a horizontal line from CurX, CurY for DeltaX pixels. *)

VAR Index, Stop, x, dx, y, Kval             : CARDINAL;
Emask, Lmask, Val                       : CHAR;

BEGIN

    IF Flag THEN        (* Flag = TRUE => Plot, else UnPlot *)
Val := 0FFX;
ELSE
Val := 0X;

END;
IF InWin.DeltaX < 18 THEN

        FOR Index := 0 TO InWin.DeltaX DO       (* For short lines *)
Plot (InWin);
INC (InWin.CurX);
END;
ELSE
x := InWin.TopX + InWin.CurX;          (* For long lines *)
y := InWin.TopY + InWin.CurY;
dx := InWin.DeltaX;
ASM
MOV  AX, 0A000H
MOV  ES, AX         (* Set up segment register *)
MOV  CX, x
AND  CX, 7
MOV  BX, 8
SUB  BX, CX
MOV  AL, 0FFH
SHR  AL, CL
MOV  Emask, AL      (* compose plotting mask *)
MOV  CX, dx
SUB  CX, BX
MOV  AX, CX
AND  AX, 7
PUSH AX             (* Save L-val *)
SUB  CX, AX
SHR  CX, 1
SHR  CX, 1
SHR  CX, 1
MOV  Kval, CX
MOV  AL, 0
POP  CX             (* retrieve L-val *)
JCXZ L0
MOV  AL, 080H
L0: DEC  CX
SAR  AL, CL
MOV  Lmask, AL
MOV  AX, y              (* Calculate offset in Video RAM *)
MOV  BX, AX
ADD  AX, AX
ADD  AX, AX
ADD  AX, BX             (* AX := 5 * Y *)
MOV  CL, 4
SHL  AX, CL             (* AX := 16 * 5 * Y *)
MOV  BX, x
SHR  BX, 1
SHR  BX, 1
SHR  BX, 1
ADD  BX, AX             (* plus X / 8 *)
MOV  AH, Emask
MOV  DX, 03CEH
MOV  AL, 8
OUT  DX, AX             (* Set plotting mask *)
MOV  AL, Val
MOV  AH, ES:[BX]
MOV  ES:[BX], AL        (* Do the plotting ... *)
INC  BX
MOV  CX, Kval
JCXZ L2
MOV  AX, 0FF08H
OUT  DX, AX
MOV  AH, Val
L1: MOV  AL, ES:[BX]
MOV  ES:[BX], AH
INC  BX
LOOP L1
L2: MOV  AH, Lmask
MOV  AL, 8
OUT  DX, AX
MOV  AL, ES:[BX]
MOV  AL, Val
MOV  ES:[BX], AL
END;
INC (InWin.CurX, dx);

END;
END DrawH;

PROCEDURE PlotChar (VAR InWin : WinData; Letter : CHAR);

(* Plot character on InWin.(CurX,CurY). *)

VAR xpos, ypos, MapOfs, VGApos, VGAseg, Pmask       : CARDINAL;
Cval                                            : CHAR;

BEGIN

IF Letter = 0AX THEN

        INC (InWin.CurY, 16);           (* Process LF *)
RETURN;

END;
IF Letter = 0DX THEN

        InWin.CurX := InWin.Indent;     (* Process CR *)
RETURN;

END;
IF InWin.CurX >= InWin.Width - ChrWid THEN

        InWin.CurX := InWin.Indent;
INC (InWin.CurY, 16);

END;
xpos := InWin.CurX + InWin.TopX;
ypos := InWin.CurY + InWin.TopY;
VGApos := 80 * ypos + SHR (xpos, 3); VGAseg := 0A000H;
MapOfs := ORD (Letter) * 16;
ASM

        PUSH ES             (* save ES *)
MOV  CX, xpos
AND  CX, 7
MOV  Cval, CL       (* nr of bits "off center" *)
MOV  BX, 0FF00H
SHR  BX, CL
MOV  Pmask, BX      (* mask to use for left and right halves *)
MOV  AX, BX
MOV  AL, 8
MOV  DX, 03CEH
OUT  DX, AX         (* set plotting mask for left part *)
MOV  CX, 16
MOV  BX, VGApos
LES  SI, BitMap     (* here are the pixels that make the tokens *)
ADD  SI, MapOfs
L0: PUSH CX
LES  AX, BitMap     (* load ES, AX is just scrap *)
MOV  AH, ES:[SI]    (* load pattern *)
MOV  CL, Cval
SHR  AX, CL         (* compose left half *)
MOV  ES, VGAseg
MOV  AL, ES:[BX]
MOV  ES:[BX], AH    (* and "print" it *)
ADD  BX, 80         (* point to next row *)
INC  SI             (* and next pixel pattern *)
POP  CX
LOOP L0             (* repeat until done *)
MOV  AX, Pmask
CMP  AL, 0          (* if Cval = 0 => perfect allignment *)
JE   ex             (*   skip second half *)
XCHG AH, AL         (* else repeat the story once more *)
MOV  AL, 8
OUT  DX, AX         (* set up mask for right half *)
MOV  CX, 16
SUB  BX, 1279       (* 16 x 80 - 1 *)
SUB  SI, CX
L1: PUSH CX
LES  AX, BitMap
MOV  AH, ES:[SI]
MOV  AL, 0
MOV  CL, Cval
SHR  AX, CL
MOV  ES, VGAseg
MOV  AH, ES:[BX]
MOV  ES:[BX], AL
ADD  BX, 80
INC  SI
POP  CX
LOOP L1

ex: POP ES
END;
INC (InWin.CurX, ChrWid); (* point to next printing position *) END PlotChar;


And here is the promised solution for the "make a box-drawing routine" problem of the previous issue. OK, the solution is in Modula-2, but since this is such a clear to understand language it will be no big deal to port this code to assembly language format.


PROCEDURE MakeBox (InWin : WinData);

(* Make a box on screen starting at (TopX, TopY). *) BEGIN

InWin.CurX := 0;
InWin.CurY := 0; (* Make sure pointers are correct *) InWin.DeltaX := InWin.Width - 1;
InWin.DeltaY := InWin.Height - 1; (* setup parameters for drawing lines *) SetColour (InWin.BoxCol);

    DrawH (InWin, TRUE);                    (* draw horizontal line *)
DrawV (InWin);                          (* draw vertical line   *)
InWin.CurX := 0;
InWin.CurY := 1;                        (* adjust coordinates   *)
DrawV (InWin);                          (* draw last vertical line  *)
DEC (InWin.CurY);
INC (InWin.CurX);                       (* adjust coordinates once more *)
DrawH (InWin, TRUE);                    (* draw final line  *)

END MakeBox;

END VgaLib.