8086 programming using TASM: pc to pc communication - tasm

.model small
.stack 100
.data
.code
mov ah,00h
mov al,0e3h
mov dx,00h
int 14h
back: nop
l1: mov ah,03h
mov dx,00h
int 14h
and ah,01h
cmp ah,01h
jne l1
mov ah,02h
mov dx,00h
int 21h
mov dl,al
mov ah,02h
int 21h
jmb back
mov ah,4ch
int 21h
end
This a pc to pc commnication receiver program. I would like to know
why it uses the mov dx,00h command and what mov al,0e3h means?

Take a look here. AX will contain the transmission parameters (baud rate etc) and DX chooses the port number. E3 = 9600 rate, no parity, two stop bits, 8 bits char size.

According to the docs I could find on int 14h,
dx determines the port numbber. So if you're using port one, you put 00h into dx. al is used for parameters of the serial communication. Check the docs for more details on the parameters.

dx is used to select the com ports. 00=com1, 01=com2.
al is used to select character size(0 and 1 bit), stop bit(2nd bit), parity bits (3rd and 4th bit) and baud rate(5,6,7 bit no.)
al=11100011=e3=8bits: no parity, one stop bit, 9600 baud rate

Related

Adobe Type 1 Encryption Algorithm in Assembly

I am trying to encrypt a text file using the adobe type 1 font encryption algorithm. However, I don't know how to properly implement the algorithm in assembly language. Please, help me if you can.
Here is the adobe type 1 font encryption algorithm:
unsigned short int r;
unsigned short int c1 =52845;
unsigned short int c2 = 22719;
unsigned char eencrypt(char plain) unsigned char plain;
{ unsigned char cipher;
cipher = (plain ^ (r >> 8));
r = (cipher + r) * c1 + c2;
return cipher;
}
Here is my code:
.model tiny
.data
filename db "file.txt", 0
bufferSize = 512
filehandle dw ?
buffer db bufferSize dup (0)
r dw 0
c1 dw 52845
c2 dw 22719
cipher dw ?
message1 db 'Cannot open file. $'
message2 db 'Cannot read file. $'
message3 db 'Cannot close file. $'
.code
org 100h
start:
call open
call read
call close
call Exit
;procedures
open:
mov ah,3DH
mov al,0
mov dx, offset filename
int 21h
jc openErr
mov filehandle, ax
ret
read: ;reads file
mov ah, 3Fh
mov bx, filehandle
mov cx, bufferSize
mov dx, offset buffer
int 21h
cmp ax,0
jc readErr
;displays content of file
call clear
mov ah, 9
mov dx, offset buffer
int 21h
ret
close:
mov ah, 3Eh
mov bx, filehandle
int 21h
jc closeErr
ret
encrypt:
; need loop to loop through each char, don't know how to do that
mov ax, [r]
shr ax, 8
mov bl, [buffer]
xor bh,bh
xor bx, ax
mov cipher, bx
mov dx, cipher
add dx, [r] ;get error: extra characters on line
imul dx, c1
add dx, c2
mov [r], dx
;decrypt:
clear: ;clears the screen
mov ax,003h
int 10h
ret
Exit:
mov ax, 4C00h
int 21h
newline: ;prints a newline
mov ah, 2
mov dl, 0DH
int 21h
mov dl, 0AH
int 21h
ret
;error messages
openErr :
call newline
lea DX,message1 ;set up pointer to error message
mov AH,9 ;display string function
int 21H ;DOS call
stc ;set error flag
ret
readErr :
call newline
lea DX,message2 ;set up pointer to error message
mov AH,9 ;display string function
int 21H ;DOS call
stc ;set error flag
ret
closeErr :
call newline
lea DX,message3 ;set up pointer to error message
mov AH,9 ;display string function
int 21H ;DOS call
stc ;set error flag
ret
end start
;encrypt:
; need loop to loop through each char, don't know how to do that
;mov ax, r
;shr ax, 8 r>>8
;mov bl, buffer bl = buffer
buffer is symbolic address, not value in the buffer. Use mov bl,[buffer] to read the value from memory. And if you want to loop over full buffer content, put that address into some register, si is often favoured for keeping pointer to the source of data (because it is hardcoded in lods instructions, and "s" may be read as "source"). If you are C++ compiler, you don't care, and you pick any spare register you have, without considering it's name.
;xor bx, ax bx = buffer ^(r>>8)
bh was not set and may be anything, ruining your calculation. Either do xor bx,bx before loading the bl from buffer, or xor bh,bh to clear bh only (tiny fraction slower on modern x86 because it must then combine bh+bl into bx), or use movzx bx,byte ptr [buffer] in previous step to zero-extend the char value into word value.
;mov cipher, bx cipher = buffer^(r>>8)
Label cipher was defined ahead of db ?, but here you are writing two bytes into memory, so it will also overwrite first byte of message1 string. And I strongly suggest to use [] every time you write into memory, even when TASM/MASM allows this kind of syntax, but I find it difficult to read (seeing [cipher] will make my brain automatically think "memory access" even with quick glance on source).
;mov cx, c1
c1 and c2 can be EQU, so they will compile as intermediate values directly into code.
;add cx, c2
That's not, what the C encrypt does (multiplication has priority over addition).
;mov dx, cipher
Again you treat cipher as word, which makes sense, but it's against the db ? (so the db needs fixing, not code here).
;add dx, r
;imul dx, cx
I would use [] brackets around r again, and the multiplication/addition order is of course wrong.
Not a bad try, but don't hesitate to uncomment that piece of code, pre-set registers with some debug values, and jump straight to it, open the binary in debugger, and single-step over it to verify it works as you did want. You would probably quickly find all those things I wrote above.
Then just turn it into loop (use any ASM book/tutorial with some example about working with arrays/strings, learn to use pointers, then it should be not that hard to finish).

How do I check if my assembly 8086 program runs well

I want to put numbers from 0 - 9 to memory cells 400h to 409h.
So for example at 400h -> 0 (put 0) and at 401h -> 1 (put 1) ..... 409h (put 9).
This is my code so far: (I dont know if it works)
IDEAL
MODEL small
STACK 100h
DATASEG
;----------
;----------
CODESEG
start:
mov ax , #data
mov ds , ax
mov es, ax
;----------
mov si , 400h
mov cx , 10
mov al , 0
agian:
mov [si],al
inc si
inc al
loop agian
;--------
exit:
mov ax,4c00h
int 21h
END start
There's a very simple way to see if your program works. Just write the values in the video memory. That way you'll know if it works.
start:
mov ax, 0B800h ;NEW
mov ds, ax
mov es, ax
;----------
mov si, 400h
mov cx, 10
mov al, 48 ;NEW value 0 -> character 0
agian:
mov [si], al
add si, 2 ;NEW 1 character occupies 2 bytes in video memory
inc al
loop agian
mov ah,00h ;NEW wait for a keystroke so you can actually see
int 16h ;NEW ... the output
If you can invest the time you could learn to use the DOS utility DEBUG.EXE. Amongst other things it allows you to single step your program and view memory .
The easiest way to check if your ASM code is working the way you expect is to run it in a debugger. If you're running on Windows, OllyDbg 2 would be a good candidate — it will show you the current values of the registers, state of the stack, etc., so you can see how they change as you step through your code. You can modify the code from inside OllyDbg too.
You can write breakpoints in your code with the int 3 instruction, or use the debugger to place breakpoints at runtime.

Bootloader memory location

This is a part of a bootloader that I am studying from
`[ORG 0x00]
[BITS 16]
SECTION .text
jmp 0x07c0:START ; set CS(segment register) to 0x07C0 and jump to START label.
TOTALSECTORCOUNT:
dw 0x02
KERNEL32SECTORCOUNT:
dw 0x02
START:
mov ax, 0x07c0
mov ds, ax ; set DS(segment register) to the address of the bootloader.
mov ax, 0xb800
mov es, ax ; set ES(segment register) to the address of the video memory starting address.
; stack initialization
mov ax, 0x0000
mov ss, ax
mov sp, 0xfffe
mov bp, 0xfffe
; clear the screen
mov si, 0
CLEARSCREEN:
mov byte[es:si], 0
mov byte[es:si + 1], 0x0a
add si, 2
cmp si, 80 * 25 * 2
jl CLEARSCREEN
; print welcome message`
I don't understand the beginning: jmp 0x07C0:START How does it set the CS register?
And what are the two variables TOTALSECTORCOUNT and KERNEL32SECTORCOUNT for? They don't appear anywhere in the bootsector file and if I remove them, the bootloader fails to load the welcome message.
Removing the parts causes the OS to fail to load. So what is the significance of that jmp statement and the two variables?
``[ORG 0x00]
[BITS 16]
jmp START
START:
mov ax, 0x07c0
mov ds, ax ; set DS(segment register) to the address of the bootloader.
mov ax, 0xb800
mov es, ax ; set ES(segment register) to the address of the video memory starting address.
; stack initialization
mov ax, 0x0000
mov ss, ax
mov sp, 0xfffe
mov bp, 0xfffe
`
I am not great with assembly and usually use the AT&T syntax also. I have however written a bootloader before.
Hopefully you have learnt about the segmented addressing system used in 16 bit applications. The cs register holds the code segment. http://wiki.osdev.org/Segmentation
jmp 0x07C0:START ;This is a long jump
jmp segment:offset
A long jump sets the cs register to segment parameter and then does a jump to the offset parameter. When you do a short jump the cs register doesn't change. I assume that it would contain 0x0. You can use a short jump but you must tell your assembler or linker where the code will be run.
EDIT: After reading the code again there is the [org 0x00] line. This sets the cs register to 0x00 by default. If you wanted to use the short jump try changing this line to [org 0x7c00]
CS should already be set to 0x7c00 by the BIOS so the line:
jmp 0x07c0:START
can be replaced by:
jmp START
The two variables you mention must be use elsewhere in the code to load the kernel. However, it appears you haven't posted the whole code here.
Without seeing the rest of the bootsector code, we cannot help.

Triple fault on stack in C code [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I am writing a toy kernel for learning purposes, and I am having a bit of trouble with it. I have made a simple bootloader that loads a segment from a floppy disk (which is written in 32 bit code), then the bootloader enables the A20 gate and turns on protected mode. I can jump to the 32 bit code fine if I write it in assembler, but if I write it in C, I get a triple fault. When I disassemble the C code I can see that the first two instructions involve setting up a new stack frame. This is the key difference between the working ASM code and the failing C code.
I am using NASM v2.10.05 for the ASM code, and GCC from the DJGPP 4.72 collection for the C code.
This is the bootloader code:
org 7c00h
BITS 16
entry:
mov [drive], dl ;Save the current drive
cli
mov ax,cs ; Setup segment registers
mov ds,ax ; Make DS correct
mov ss,ax ; Make SS correct
mov bp,0fffeh
mov sp,0fffeh ;Setup a temporary stack
sti
;Set video mode to text
;===================
mov ah, 0
mov al, 3
int 10h
;===================
;Set current page to 0
;==================
mov ah, 5
mov al, 0
int 10h
;==================
;Load the sector
;=============
call load_image
;=============
;Clear interrupts
;=============
cli
;=============
;Disable NMIs
;============
in ax, 70h
and ax, 80h ;Set the high bit to 1
out 70h, ax
;============
;Enable A20:
;===========
mov ax, 02401h
int 15h
;===========
;Load the GDT
;===========
lgdt [gdt_pointer]
;===========
;Clear interrupts
;=============
cli
;=============
;Enter protected mode
;==================
mov eax, cr0
or eax, 1 ;Set the low bit to 1
mov cr0, eax
;==================
jmp 08h:clear_pipe ;Far jump to clear the instruction queue
;======================================================
load_image:
reset_drive:
mov ah, 00h
; DL contains *this* drive, given to us by the BIOS
int 13h
jc reset_drive
read_sectors:
mov ah, 02h
mov al, 01h
mov ch, 00h
mov cl, 02h
mov dh, 00h
; DL contains *this* drive, given to us by the BIOS
mov bx, 7E0h
mov es, bx
mov bx, 0
int 13h
jc read_sectors
ret
;======================================================
BITS 32 ;Protected mode now!
clear_pipe:
mov ax, 10h ; Save data segment identifier
mov ds, ax ; Move a valid data segment into the data segment register
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax ; Move a valid data segment into the stack segment register
mov esp, 90000h ; Move the stack pointer to 90000h
mov ebp, esp
jmp 08h:7E00h ;Jump to the kernel proper
;===============================================
;========== GLOBAL DESCRIPTOR TABLE ==========
;===============================================
gdt: ; Address for the GDT
gdt_null: ; Null Segment
dd 0
dd 0
gdt_code: ; Code segment, read/execute, nonconforming
dw 0FFFFh ; LIMIT, low 16 bits
dw 0 ; BASE, low 16 bits
db 0 ; BASE, middle 8 bits
db 10011010b ; ACCESS byte
db 11001111b ; GRANULARITY byte
db 0 ; BASE, low 8 bits
gdt_data: ; Data segment, read/write, expand down
dw 0FFFFh
dw 0
db 0
db 10010010b
db 11001111b
db 0
gdt_end: ; Used to calculate the size of the GDT
gdt_pointer: ; The GDT descriptor
dw gdt_end - gdt - 1 ; Limit (size)
dd gdt ; Address of the GDT
;===============================================
;===============================================
drive: db 00 ;A byte to store the current drive in
times 510-($-$$) db 00
db 055h
db 0AAh
And this is the kernel code:
void main()
{
asm("mov byte ptr [0x8000], 'T'");
asm("mov byte ptr [0x8001], 'e'");
asm("mov byte ptr [0x8002], 's'");
asm("mov byte ptr [0x8003], 't'");
}
The kernel simply inserts those four bytes into memory, which I can check as I am running the code in a VMPlayer virtual machine. If the bytes appear, then I know the code is working. If I write code in ASM that looks like this, then the program works:
org 7E00h
BITS 32
main:
mov byte [8000h], 'T'
mov byte [8001h], 'e'
mov byte [8002h], 's'
mov byte [8003h], 't'
hang:
jmp hang
The only differences are therefore the two stack operations I found in the disassembled C code, which are these:
push ebp
mov ebp, esp
Any help on this matter would be greatly appreciated. I figure I am missing something relatively minor, but crucial, here, as I know this sort of thing is possible to do.
Try using the technique here:
Is there a way to get gcc to output raw binary?
to produce a flat binary of the .text section from your object file.
I'd try moving the address of your protected mode stack to something else - say 0x80000 - which (according to this: http://wiki.osdev.org/Memory_Map_(x86)) is RAM which is guaranteed free for use (as opposed to the address you currently use - 0x90000 - which apparently may not be present - depending a bit on what you're using as a testing environment).

NASM jmp wonkiness

I'm writing a Forth inner interpreter and getting stuck at what should be the simplest bit. Using NASM on Mac (macho)
msg db "k thx bye",0xA ; string with carriage return
len equ $ - msg ; string length in bytes
xt_test:
dw xt_bye ; <- SI Starts Here
dw 0
db 3,'bye'
xt_bye dw $+2 ; <- Should point to...
push dword len ; <-- code here
push dword msg ; <--- but it never gets here
push dword 1
mov eax, 0x4 ; print the msg
int 80h
add esp, 12
push dword 0
mov eax, 0x1 ; exit(0)
int 80h
_main:
mov si,xt_test ; si points to the first xt
lodsw ; ax now points to the CFA of the first word, si to the next word
mov di,ax
jmp [di] ; jmp to address in CFA (Here's the segfault)
I get Segmentation Fault: 11 when it runs. As a test, I can change _main to
_main:
mov di,xt_bye+2
jmp di
and it works
EDIT - Here's the simplest possible form of what I'm trying to do, since I think there are a few red herrings up there :)
a dw b
b dw c
c jmp _my_actual_code
_main:
mov si,a
lodsw
mov di,ax
jmp [di]
EDIT - After hexdumping the binary, I can see that the value in b above is actually 0x1000 higher than the address where label c is compiled. c is at 0x00000f43, but b contains 0x1f40
First, it looks extremely dangerous to use the 'si' and 'di' 16-bit registers on a modern x86 machine which is at least 32-bit.
Try using 'esi' and 'edi'. You might be lucky to avoid some of the crashes when 'xt_bye' is not larger than 2^16.
The other thing: there is no 'RET' at the end of xt_bye.
One more: see this linked question Help with Assembly. Segmentation fault when compiling samples on Mac OS X
Looks like you're changing the ESP register to much and it becomes unaligned by 16 bytes. Thus the crash.
One more: the
jmp [di]
may not load the correct address because the DS/ES regs are not used thus the 0x1000 offset.

Resources