Surviving the 8086 Assembly Course
The blog series which contains all the core components to know so that you can pass your 8086 assembly lab course
Pretalk
If you’re studying in Bangladesh or India, there’s a good chance that your assembly language practical course uses 8086 Assembly with the EMU8086 software. This approach is quite common in academic settings. However, it’s also true that assembly language isn’t widely used in most modern development workflows, so many instructors may have limited hands-on experience with it beyond their own education. As a result, some of the teaching may focus more on theory than practical, real-world applications.
But you have to pass this course with and you cannot bullshit your way through considering the examiner’s theoratical knowledge will kick off the bullshit sensor in their brain when you try to do so. So we will focus on only the necessary things we need to know to make sure we don’t fail and we don’t trip their bullshit sensor as well.
Knowledge needed
If you are using EMU8086 in the exam you can get pass by using the built in snippets but most teachers will just cut some portions of the program and make you rewrite that on the spot, in that case you need to know some theory and coding tricks before you even try to attempt something
- Registers and memory of the 8086 microprocessor
- Sections of assembly code
- Which instructions with which memory can work and which combinations of source and destinations are legal
- The AH value that does special functions that you may need to use
- The process of coding it in any low level language like C
- Commenting the code frequently to make the code more readable and use the C program as your coding reference
8086 Registers
8086 microprocessor is a 16bit microprocessor and there are three kinds of registers in 8086 microprocessors. they are
- General Purpose Registers
16-bit | High byte (8-bit) | Low byte (8-bit) | Common Use |
---|---|---|---|
AX | AH | AL | Accumulator (for arithmetic) |
BX | BL | BH | Base (used in addressing) |
CX | CH | CL | Counter (used in loops, shifts) |
DX | DH | DL | Data (used in I/O, multiplication) |
- Index Pointer Registers
Register | Purpose |
---|---|
SP | Stack Pointer (points to top of the stack) |
BP | Base Pointer (used to access parameters in stack frames) |
SI | Source Index (used in string/memory operations) |
DI | Destination Index (used in string/memory operations) |
- Segment Registers
Register | Purpose |
---|---|
CS | Code Segment (where instructions are fetched from) |
DS | Data Segment (default for variables) |
SS | Stack Segment (used with the stack) |
ES | Extra Segment (used for string operations) |
- Flag Registers
Flag | Description |
---|---|
CF | Carry Flag |
ZF | Zero Flag |
SF | Sign Flag |
OF | Overflow Flag |
PF | Parity Flag |
AF | Auxiliary Carry (used in BCD) |
DF | Direction Flag (used in string ops) |
IF | Interrupt Enable Flag |
Code Sections
In 8086 Assembly, the program is typically divided into several segments, each with a specific purpose.
Here’s a breakdown of the most commonly used segments:
.model
The .model
directive specifies the memory model of the program — it tells the assembler how code and data are organized.
Common Memory Models:
Memory Model | Description |
---|---|
`.model tiny` | Code + data fit in 1 segment (COM programs) |
`.model small` | Code and data each have one segment |
`.model medium` | Code can span multiple segments, data in one |
`.model large` | Code and data both can be in multiple segments |
For beginners, .model small
is the most commonly used.
1
.model small
.data
The .data
segment is where you declare initialized variables (data that has a known starting value).
Examples:
1
2
3
.data
msg db 'Hello, World$', 0
number dw 1234h
.stack
The .stack
segment reserves memory for the stack, which is used for function calls, pushing/popping values, etc.
You define how much memory (in bytes) you want to allocate for it:
1
.stack 100h ; reserve 256 bytes for the stack
Stack operations use SP
(Stack Pointer) and SS
(Stack Segment) registers.
.code
This is where you write your actual instructions (the program logic). It corresponds to the Code Segment (CS) in memory.
Typical Structure:
1
2
3
4
5
6
7
8
9
10
.code
main proc
mov ax, @data
mov ds, ax
; Program codes
mov ah, 4ch
int 21h ; exit to DOS
main endp
Memory Permutations
In 8086 (and most x86 architectures), you cannot use two memory operands in a single instruction. For example:
Valid example:
1
2
MOV AX, [BX] ; move from memory at address in BX to AX
MOV [SI], AX ; move from AX into memory at address in SI
Invalid (two memory operands) example:
1
MOV [BX], [SI] ; illegal: both source and destination are memory
Why this happens:
In x86 architecture, the CPU’s instruction set encoding doesn’t support directly transferring data from one memory location to another in a single instruction. It requires the CPU to work with a register as an intermediary.
So you must break it into two steps:
1
2
MOV AX, [SI] ; load from source memory
MOV [BX], AX ; store into destination memory
General Rule of Thumb:
Only one memory operand is allowed in most x86 instructions (MOV, ADD, SUB, etc.) — the other operand must be a register or an immediate value.
Allowed Combinations in MOV:
- Register ↔ Register
- Register ↔ Memory
- Register ↔ Immediate
not allwed in MOV
- Memory ←→ Memory
One trick is to use register to register for all instructions. as that is allowd in all of the instructions
AH functions
DOS Interrupt 21h Functions are the one used in AH and that value does some particular task. The task corresponding to the value is
AH Value | Function Name | Purpose |
---|---|---|
01h | Input character (with echo) | Waits for keypress and echoes it on screen |
02h | Display character | Prints the character in DL |
06h | Direct console I/O | Input/output without echo |
07h | Input character (no echo) | Like 01h but without echoing |
08h | Input character (no echo, no wait) | Reads a key only if one is pressed |
09h | Display string | Displays a $ -terminated string from DX |
0Ah | Buffered string input | Reads string input into a buffer (first byte = max length) |
0Eh | Select default drive | DL = drive number (0=A, 1=B, etc.) |
25h | Set interrupt vector | Change ISR for a given interrupt |
2Ah | Get system date | Returns date in CX, DX, AL |
2Ch | Get system time | Returns time in CX, DX |
31h | Terminate and stay resident | Keeps part of the program in memory (TSR) |
4Ch | Terminate program | End program with optional return code in AL |
Conclusion
This are all the theories that are absolutely necessary to make sure you can at least get past the minimum requirement to at least read the template codes in the software and get past the coding task.