Lab Content ..: Programming Language
Lab Content ..: Programming Language
Lab Content ..: Programming Language
Project ………………………………………………………………………….
8086 Microprocessor Emulator, also known as EMU8086, is an emulator of the program 8086
microprocessor. It is developed with a built-in 8086 assembler. This application is able to run
programs on both PC desktops and laptops. This tool is primarily designed to copy or emulate
hardware. These include the memory of a program, CPU, RAM, input and output devices, and
even the display screen.
There are instructions to follow when using this emulator. It can be executed into one of the two
ways: backward or forward. There are also examples of assembly source code included. With this,
it allows the programming of assembly language, reverse engineering, hardware architecture,
and creating miniature operating system (OS).
The user interface of 8086 Microprocessor Emulator is simple and easy to manage. There are five
major buttons with icons and titles included. These are “Load”, “Reload”, “Step Back”, “Single
Step”, and “Run”. Above those buttons is the menu that includes “File”, “View”, “Virtual Devices”,
“Virtual Drive”, and “Help”. Below the buttons is a series of choices that are usually in numbers
and codes. At the leftmost part is an area called “Registers” with an indication of either “H” or
“L”. The other side is divided into two, which enables users to manually reset, debug, flag, etc.
• Type the above code using a text editor and save it as hello.asm.
• Make sure that you are in the same directory as where you saved hello.asm.
• To assemble the program, type nasm -f elf hello.asm
• If there is any error, you will be prompted about that at this stage. Otherwise, an object
file of your program named hello.o will be created.
• To link the object file and create an executable file named hello, type ld -m elf_i386 -s -o
hello hello.o
• Execute the program by typing ./hello
If you have done everything correctly, it will display 'Hello, world!' on the screen.
Interestingly, if you replace the section keyword with segment, you will get the same result. Try
the following code −
segment .text ;code segment
global _start ;must be declared
for linker _start: ;tell linker entry point
mov edx,len ;message length
mov ecx,msg ;message to write
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
segment .data ;data segmentmsgdb 'Hello, world!',0xa ;our dear stringlen
equ$ - msg ;length of our dear string
When the above code is compiled and executed, it produces the following result −
Hello, world!
Memory Segments
A segmented memory model divides the system memory into groups of independent segments
referenced by pointers located in the segment registers. Each segment is used to contain a
specific type of data. One segment is used to contain instruction codes, another segment stores
the data elements, and a third segment keeps the program stack.
In the light of the above discussion, we can specify various memory segments as −
• Data segment − It is represented by .data section and the .bss. The .data section is used
to declare the memory region, where data elements are stored for the program. This
section cannot be expanded after the data elements are declared, and it remains static
throughout the program.
• The .bss section is also a static memory section that contains buffers for data to be
declared later in the program. This buffer memory is zero-filled.
• Code segment − It is represented by .text section. This defines an area in memory that
stores the instruction codes. This is also a fixed area.
• Stack − This segment contains data values passed to functions and procedures within the
program.
• Register to register
• Memory to register
• Register to memory
• Register to constant data
• Memory to constant data
However, like other instructions, memory-to-memory operations are not possible using
ADD/SUB instructions. An ADD or SUB operation sets or clears the overflow and carry flags.
Example
The following example will ask two digits from the user, store the digits in the EAX and EBX
register, respectively, add the values, store the result in memory location 'res' and finally display
the result.
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
segment .data
When the above code is compiled and executed, it produces the following result −
Enter a digit:3
Please enter a second digit:4
The sum is:7
section.text
global _start ;must be declared for using
gcc_start: ;tell linker entry point
moveax,'3' sub eax, '0'
mov ebx, '4' sub ebx, '0'
add eax, ebx addeax, '0'
mov [sum], eax
movecx,msg
movedx, len
movebx,1;file descriptor (stdout)
moveax,4;system call number (sys_write)
int0x80;call kernel
movecx,sum
movedx, 1
movebx,1;file descriptor (stdout)
moveax,4;system call number (sys_write)
int0x80;call kernel
moveax,1;system call number (sys_exit)
int0x80;call kernel
section .data msg db "The sum is:", 0xA,0xD len
equ $ - msg segment .bss sum resb 1
When the above code is compiled and executed, it produces the following result −
The sum is:7
Example
MOV AL, 10MOV DL, 25MUL DL...MOV DL, 0FFH; DL= -1MOV AL, 0BEH; AL = -66IMUL DL
Example
The following example multiplies 3 with 2, and displays the result −
section.text
global _start ;must be declared for using
gcc_start: ;tell linker entry point
mov al,'3' sub al, '0'
mov bl, '2' sub bl, '0' mul bl add al, '0'
mov [res], al
mov ecx,msg
mov edx, len
mov ebx,1 ;file descriptor (stdout)
moveax,4;system call number (sys_write)
int0x80;call kernel
movecx,res
movedx, 1
movebx,1;file descriptor (stdout)
moveax,4;system call number (sys_write)
int0x80;call kernel
moveax,1;system call number (sys_exit)
int0x80;call kernel
section .data
msg db "The result is:", 0xA,0xD len
equ $- msg segment .bssres resb 1
When the above code is compiled and executed, it produces the following result −
The result is:6
Sr.N Scenarios
o.
; Multiple Input
.MODEL SMALL
.STACK 100H
.CODE
MOV BH, AL
MOV AH, 2
MOV DL, 0AH
INT 21H ; NEWLINE
MOV DL, 0DH
INT 21H
MOV DL, BH
INT 21H
EXIT:
MOV AH, 4CH
INT 21H
MAIN ENDP
END MAIN
.MODEL SMALL
.STACK 100h
.DATA
n_line DB 0AH,0DH,"$" ;for new line
.CODE
MAIN PROC
MOV AX,@DATA
MOV DS,AX
MOV DL,'A'
MOV AH,2
INT 21H ;print 'A'
LEA DX,n_line ;lea means least effective address
MOV AH,9
INT 21H ;print new line
MOV DL,'B'
MOV AH,2
INT 21H ;print 'B'
MAIN ENDP
END MAIN
mov rdi,the_secret_message
call puts ; write our string to the screen
ret
the_secret_message:
db 0x59
db 0x75
db 0x70
db 0 ;<- zero byte marks end of string
That's a pretty atrocious way to write strings, so the assembler supports a bunch of other
syntaxes. These are all equivalent:
db 0x4D, 0x6F, 0x6F, 0x73, 0x65, 0 db 'M', 'o', 'o', 's', 'e', 0 db 'Moose', 0
In the assembler, single and double quotes are interchangable, unlike in C++, where single
quote like 'M' is an integral value 0x4D, but double quote "M" is a pointer to a zero-terminated
string {0x4D,0}. Also unlike in C++, "\n" doesn't give a newline, it prints "\n"! To get an actual
newline, you need to use 0xA (this is ASCII "LF", new line). Don't forget the zero byte to end the
string.
db 'Moose',0xA
db '... and squirrel.',0
Keep in mind that puts adds a newline at the end of the string. Call printf to avoid the newline.
You can access an individual byte from memory with the syntax BYTE [address]. Most
instructions want DWORDs, not BYTEs, so you need to use a BYTE-friendly instruction like
"movzx" (move with zero-extend):
movzx reg,BYTE[address]
Accessing data as bytes is useful for string processing, or to understand what really shows up in
memory.
For example, here I'm defining a short 3-byte string, and reading one byte out:
movzx eax,BYTE[myString + 2] ; read this byte into eax
ret
section .data
myString:
db 'w','o','a'
These are all equivalent ways to get the same 3-byte string:
section .data
myString:
db 'woa',0 ; need the trailing zero to mark the end of the string...
Here's an example where we load a byte from the middle of an integer. Note that this returns
0xa2, since byte 0 is the 0xa0--the little byte--on our little-endian x86 machines.
section .data
myInt:
dd 0xa3a2a1a0 ; "data DWORD" containing this value
Variable Strings
There are these handy C functions gets and puts that read or write strings to the screen. They
both take just one argument, a pointer to the string data to read or write. For example, I can
store a modifiable string statically, in "section .data":
extern gets
extern puts
mov rdi,mystring
call gets
mov rdi,mystring
call puts
ret
section .data
mystring:
times 100 db 'v'
*Or* I can allocate space on the stack to store the string:
extern gets
extern puts
mov rdi,rsp
call gets ; read into our string
mov rdi,rsp
call puts ; write our string to the screen
Or I can call "malloc" to allocate space for the string. I need to use a preserved register to hang
onto the allocated pointer; here I'm using r12.
extern gets
extern puts
extern malloc, free
mov rdi,100
call malloc
mov r12,rax ; <- malloc returns the pointer in rax
mov rdi,r12
call gets ; read into our string
mov rdi,r12
call puts ; write our string to the screen
mov rdi,r12
call free ; dispose of our copy of the string
LEA DX,S1
MOV AH,9
INT 21H
MOV AH,1
INT 21H
MOV V1,AL
MOV AH,2
MOV DL,0DH
INT 21H
MOV DL,0AH
INT 21H
LEA DX,S2
MOV AH,9
INT 21H
MOV AH,1
INT 21H
MOV V2,AL
MOV AH,2
MOV DL,0DH
INT 21H
MOV DL,0AH
INT 21H
LEA DX,S3
MOV AH,9
INT 21H
MOV AL,V1
ADD AL,V2
SUB AL,30H
MOV AH,2
MOV DL,AL
INT 21H
MOV AH,2
MOV DL,0DH
INT 21H
MOV DL,0AH
INT 21H
LEA DX,S4
MOV AH,9
INT 21H
MOV AL,V1
SUB AL,V2
ADD AL,30H
MOV AH,2
MOV DL,AL
INT 21H
MOV AH,4CH
INT 21H
MAIN ENDP
END MAIN
When the above code is compiled and executed, it produces the following result −