I am currently playing around with x86 assembler since I wanted to refresh my skills for low level programming :-). For testing purposes I tried to write a function that just prints out a given string. The printing function itself works fine. In a further step I wanted to load a second assembler program from disk jump to it and just print out a text. Loading from disk at jump to the address works fine.
Here is the given scenario:
[... loading from disk etc ... program is loaded to 0x7e0:0001]
jmp 0x7e0:0001
[... context of other asm ...]
jmp Start
;data fields
msg db "Hello World!",0
Start:
xor si, si ; clear SI register
mov si, msg ; load message to SI register
call Print
cli
hlt ; halt the system
Print:
.PrintLoop:
lodsb ; load byte from SI register
or al, al ; check if 0 byte
jz short .PrintDone ; if so - stop
mov ah, 0Ah ; function - print text to cursor
int 0x10 ; BIOS interrupt
jmp .PrintLoop ; continue with next char
.PrintDone:
ret
All of this program is working fine. The only problem that I face is, that no text is printed. During debugging I saw that the print function immediately jumps to the .PrintDone label since there seems to be no data in SI and therefore lodsb loads nothing to al (besides null byte).
I was thinking about the fact, that there might be something wrong with the data segment.
Thus, I added the following line at the beginning of the Start-Routine:
xor ax, ax ; clear ax register
mov ax, cs
mov ds, ax ; set data segment pointer
But this changed nothing regarding the programs behaviour. Nothing is printed.
Inspecting the CPU registers when execution reaches halt instruction, gives the following:
EAX=00000a00 EBX=00000000 ECX=00000002 EDX=00000000
ESI=00000026 EDI=00000000 EBP=00000000 ESP=0000ffff
EIP=00000036 EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=1
ES =07e0 00007e00 0000ffff 00009300
CS =07e0 00007e00 0000ffff 00009b00
SS =9000 00090000 0000ffff 00009300
DS =07e0 00007e00 0000ffff 00009300
Do you have any clue what’s going on here?
[EDIT – PROBLEM RESOLVED]
Replacing:
mov ah, 0Ah -> mov ah, 0xE
fixes the problem!
Best
Sebastian
There are a few problems.
First, you don’t properly set the registers for function 0Ah. You have to set
bhto the page number (0), andcxto the repeat count (1).Second, this BIOS function doesn’t advance the cursor position and all characters get printed into the same location on the screen, overwriting each other, which should lead to only ‘!’ visible since it’s the last character.
I advise to use function 0Eh instead.
Third, you don’t initialize the direction flag (
flags.df) whichlodsbrelies upon. You should usecldto resetdf.Fourth, I don’t see all the code, but you should use the proper
orgdirective to generate correct offsets for instructions and data.Also,
NMIsandSMIswill causehltcompletion and the code that follows will execute (and what follows is yourPrint). You want to executehltin a loop.With these fixes we arrive at:
The binary which you get by compiling the above with
nasm blah.asm -f bin -o blah.binshould then be loaded at0x7e0:0001and jumped to withjmp 0x7e0:0001.