Lab Content ..: Programming Language

Download as pdf or txt
Download as pdf or txt
You are on page 1of 25

Table of Contents

Lab Content …………………………………………………………………..

LAB 1: INTRODUCTION TO EMU8086 EMULATOR

LAB 2: INTRODUCTION TO BASIC SYNTAX OF ASSEMBLY LANGUAGE


PROGRAMMING
LAB 3: ARITHMETIC & INPUT-OUTPUT INSTRUCTIONS IN ASSEMBLY
LANGUAGE
LAB 4: MULTIPLE INPUT-OUTPUT, VARIABLE AND NEW LINE CREATION
LAB 5: STRING PROCESSING IN ASSEMBLY LANGUAGE
LAB 6: PERFORMING ADDITION AND SUBTRACTION

Project ………………………………………………………………………….

Name: A Simple Calculator


Attached Video of Project
LAB 1: INTRODUCTION TO EMU8086 EMULATOR

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.

LAB 2: INTRODUCTION TO BASIC SYNTAX OF ASSEMBLY LANGUAGE


PROGRAMMING
An assembly program can be divided into three sections −

• The data section,


• The bss section, and
• The text section.
The data Section
The data section is used for declaring initialized data or constants. This data does not change at
runtime. You can declare various constant values, file names, or buffer size, etc., in this section.
The syntax for declaring data section is −
section.data
The bss Section
The bss section is used for declaring variables. The syntax for declaring bss section is −
section.bss
The text section
The text section is used for keeping the actual code. This section must begin with the declaration
global _start, which tells the kernel where the program execution begins.
The syntax for declaring text section is −
section.text global _start_start:
Comments
Assembly language comment begins with a semicolon (;). It may contain any printable character
including blank. It can appear on a line by itself, like −
; This program displays a message on screen
or, on the same line along with an instruction, like −
add eax, ebx ; adds ebx to eax
Assembly Language Statements
Assembly language programs consist of three types of statements −

• Executable instructions or instructions,


• Assembler directives or pseudo-ops, and
• Macros.
The executable instructions or simply instructions tell the processor what to do. Each instruction
consists of an operation code (opcode). Each executable instruction generates one machine
language instruction.
The assembler directives or pseudo-ops tell the assembler about the various aspects of the
assembly process. These are non-executable and do not generate machine language instructions.
Macros are basically a text substitution mechanism.
Syntax of Assembly Language Statements
Assembly language statements are entered one statement per line. Each statement follows the
following format −
[label] mnemonic [operands] [;comment]
The fields in the square brackets are optional. A basic instruction has two parts, the first one is
the name of the instruction (or the mnemonic), which is to be executed, and the second are the
operands or the parameters of the command.
Following are some examples of typical assembly language statements −
INC COUNT ; Increment the memory variable COUNT
MOV TOTAL, 48 ; Transfer the value 48 in the
; memory variable TOTAL
ADD AH, BH ; Add the content of the
; BH register into the AH register
AND MASK1, 128 ; Perform AND operation on the
; variable MASK1 and 128
ADD MARKS, 10 ; Add 10 to the variable MARKS
MOV AL, 10 ; Transfer the value 10 to the AL register
The Hello World Program in Assembly
The following assembly language code displays the string 'Hello World' on the screen −
section.text
global _start ;must be declared for linker (ld)
_start: ;tells linker entry point
movedx,len ;message length
movecx,msg ;message to write
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.datamsg db 'Hello, world!', 0xa ;string to be printedlen
equ $ - msg ;length of the string
When the above code is compiled and executed, it produces the following result −
Hello, world!
Compiling and Linking an Assembly Program in NASM
Make sure you have set the path of nasm and ld binaries in your PATH environment variable.
Now, take the following steps for compiling and linking the above program −

• 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.

LAB 3: ARITHMETIC & INPUT-OUTPUT INSTRUCTIONS IN ASSEMBLY


LANGUAGE
The INC Instruction
The INC instruction is used for incrementing an operand by one. It works on a single operand that
can be either in a register or in memory.
Syntax
The INC instruction has the following syntax −
INC destination
The operand destination could be an 8-bit, 16-bit or 32-bit operand.
Example
INC EBX ; Increments 32-bit register
INC DL ; Increments 8-bit register
INC [count] ; Increments the count variable
The DEC Instruction
The DEC instruction is used for decrementing an operand by one. It works on a single operand
that can be either in a register or in memory.
Syntax
The DEC instruction has the following syntax −
DEC destination
The operand destination could be an 8-bit, 16-bit or 32-bit operand.
Example
segment .data
count dw 0
value db 15
segment .text
inc [count]
dec [value]
mov ebx, count
inc word [ebx]
mov esi, value
dec byte [esi]

The ADD and SUB Instructions


The ADD and SUB instructions are used for performing simple addition/subtraction of binary data
in byte, word and doubleword size, i.e., for adding or subtracting 8-bit, 16-bit or 32-bit operands,
respectively.
Syntax
The ADD and SUB instructions have the following syntax −
ADD/SUBdestination, source
The ADD/SUB instruction can take place between −

• 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

msg1 db "Enter a digit ", 0xA,0xD


len1 equ $- msg1
msg2 db "Please enter a second digit", 0xA,0xD
len2 equ $- msg2
msg3 db "The sum is: "
len3 equ $- msg3segment .bss
num1 resb 2
num2 resb 2
res resb 1
section.text
global _start ;must be declared for using
gcc_start: ;tell linker entry point
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg1
mov edx, len1
int 0x80
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num1
mov edx, 2
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg2
mov edx, len2
int 0x80 mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num2
mov edx, 2
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg3
mov edx, len3
int 0x80
; moving the first number to eax register and second number to ebx
; and subtracting ascii '0' to convert it into a decimal number
mov eax, [num1] sub eax, '0' mov ebx, [num2] sub ebx, '0' ; add eax and ebx add eax, ebx
; add '0' to to convert the sum from decimal to ASCII add eax, '0' ; storing the sum in memory
location res
mov [res], eax ; print the sum
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, res
mov edx, 1
int 0x80exit:
mov eax, SYS_EXIT xor ebx, ebx
int 0x80

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

The program with hardcoded variables –

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

The MUL/IMUL Instruction


There are two instructions for multiplying binary data. The MUL (Multiply) instruction handles
unsigned data and the IMUL (Integer Multiply) handles signed data. Both instructions affect the
Carry and Overflow flag.
Syntax
The syntax for the MUL/IMUL instructions is as follows −
MUL/IMUL multiplier
Multiplicand in both cases will be in an accumulator, depending upon the size of the multiplicand
and the multiplier and the generated product is also stored in two registers depending upon the
size of the operands. Following section explains MUL instructions with three different cases −
Sr.N Scenarios
o.

1 When two bytes are multiplied −


The multiplicand is in the AL register, and the multiplier is a byte in the memory or in
another register. The product is in AX. High-order 8 bits of the product is stored in AH
and the low-order 8 bits are stored in AL.

2 When two one-word values are multiplied −


The multiplicand should be in the AX register, and the multiplier is a word in memory or
another register. For example, for an instruction like MUL DX, you must store the
multiplier in DX and the multiplicand in AX.
The resultant product is a doubleword, which will need two registers. The high-order
(leftmost) portion gets stored in DX and the lower-order (rightmost) portion gets stored
in AX.

3 When two doubleword values are multiplied −


When two doubleword values are multiplied, the multiplicand should be in EAX and the
multiplier is a doubleword value stored in memory or in another register. The product
generated is stored in the EDX:EAX registers, i.e., the high order 32 bits gets stored in
the EDX register and the low order 32-bits are stored in the EAX register.

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

The DIV/IDIV Instructions


The division operation generates two elements - a quotient and a remainder. In case of
multiplication, overflow does not occur because double-length registers are used to keep the
product. However, in case of division, overflow may occur. The processor generates an interrupt
if overflow occurs.
The DIV (Divide) instruction is used for unsigned data and the IDIV (Integer Divide) is used for
signed data.
Syntax
The format for the DIV/IDIV instruction −
DIV/IDIVdivisor
The dividend is in an accumulator. Both the instructions can work with 8-bit, 16-bit or 32-bit
operands. The operation affects all six status flags. Following section explains three cases of
division with different operand size −

Sr.N Scenarios
o.

1 When the divisor is 1 byte −


The dividend is assumed to be in the AX register (16 bits). After division, the quotient
goes to the AL register and the remainder goes to the AH register.

2 When the divisor is 1 word −


The dividend is assumed to be 32 bits long and in the DX:AX registers. The high-order
16 bits are in DX and the low-order 16 bits are in AX. After division, the 16-bit quotient
goes to the AX register and the 16-bit remainder goes to the DX register.

3 When the divisor is doubleword −


The dividend is assumed to be 64 bits long and in the EDX: EAX registers. The high-order
32 bits are in EDX and the low-order 32 bits are in EAX. After division, the 32-bit quotient
goes to the EAX register and the 32-bit remainder goes to the EDX register.
Example
The following example divides 8 with 2. The dividend 8 is stored in the 16-bit AX register and the
divisor 2 is stored in the 8-bit BL register.
Section .text
global _start ;must be declared for using
gcc_start: ;tell linker entry point
movax,'8' sub ax, '0'
mov bl, '2' sub bl, '0'
div bl addax, '0'
mov [res], ax
movecx,msg
movedx, len
movebx,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:4

LAB 4: MULTIPLE INPUT-OUTPUT, VARIABLE AND NEW LINE CREATION

Multiple input in Assembly Language

; Multiple Input

.MODEL SMALL
.STACK 100H
.CODE

MAIN PROC ;PROC = Procedure

MOV AH, 1 ; INPUT FUNCTION


INT 21H ; INT = Interupt
MOV BL, AL
INT 21H

MOV BH, AL

MOV AH, 2
MOV DL, 0AH
INT 21H ; NEWLINE
MOV DL, 0DH
INT 21H

MOV AH, 2 ; OUTPUT FUNCTION


MOV DL, BL
INT 21H

MOV DL, BH
INT 21H

EXIT:
MOV AH, 4CH
INT 21H
MAIN ENDP
END MAIN

New Line in Assembly Language

.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

LAB 5: STRING PROCESSING IN ASSEMBLY LANGUAGE


Constant Strings
The bottom line is a C string is just a region of memory with some ASCII characters in it. One
ASCII character is one byte, and a zero byte indicates the end of the string. So any way you can
create bytes with known values, you can create strings too. Here we're using the handy C
function puts to print the string onto the screen.
extern puts

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.

Static Bytes & Strings

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:

db 0x77 db 'w' db 'w','o','a' db 'woa' db "woa"


db 0x6f db 'o'
db 0x61 db 'a'
There are several standard functions that take a "C string": a pointer to a bunch of ASCII bytes,
followed by a zero byte. "puts" is one such function, and it prints the string you pass it plus a
newline. We can call puts to print out our string like this:

mov rdi,myString ; points to string constant below


extern puts
call puts
ret

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.

movzx eax,BYTE[myInt + 2] ; read this byte into eax


ret

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

sub rsp,100 ; allocate 100 bytes of stack space

mov rdi,rsp
call gets ; read into our string
mov rdi,rsp
call puts ; write our string to the screen

add rsp,100; give back stack space


ret

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

push r12 ; preserve main's copy on the stack

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

pop r12 ; restore main's copy of this register


ret

LAB 6: PERFORMING ADDITION AND SUBTRACTION


.MODEL SMALL
.STACK 100H
.DATA
S1 DB "ENTER THE 1ST DIGIT: $ "
S2 DB "ENTER THE 2ND DIGIT: $ "
S3 DB "SUM OF 1ST & 2ND DIGIT: $"
S4 DB "SUB OF 1ST & 2ND DIGIT: $"
V1 DB ?
V2 DB ?
.CODE
MAIN PROC
MOV AX,@DATA
MOV DS,AX

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 −

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy