diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..eb509bc74b20e1a50268aa05d5b9d6130627acd2 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,40 @@ +# Compiler and Assembler +CC = gcc +ASM = nasm +CFLAGS = -m32 +ASMFLAGS = -f elf + +# Files and Targets +TARGETS = task1 task2 +DRIVER = driver.c +ASM_IO = asm_io.asm + +all: $(TARGETS) + +# Rule to build task1 +task1: driver.o task1.o asm_io.o + $(CC) $(CFLAGS) -o task1 driver.o task1.o asm_io.o + +# Rule to build task2 +task2: driver.o task2.o asm_io.o + $(CC) $(CFLAGS) -o task2 driver.o task2.o asm_io.o + +# Compile the driver C file +driver.o: $(DRIVER) + $(CC) $(CFLAGS) -c $(DRIVER) -o driver.o + +# Assemble task1.asm +task1.o: task1.asm + $(ASM) $(ASMFLAGS) task1.asm -o task1.o + +# Assemble task2.asm +task2.o: task2.asm + $(ASM) $(ASMFLAGS) task2.asm -o task2.o + +# Assemble asm_io.asm +asm_io.o: $(ASM_IO) + $(ASM) $(ASMFLAGS) asm_io.asm -o asm_io.o + +# Clean rule to remove all generated files +clean: + rm -f *.o $(TARGETS) diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ec4d1ebd536c5c5afa18d9ef78e714d5e9070745 --- /dev/null +++ b/src/README.md @@ -0,0 +1,64 @@ +Assembler Program: task1.asm +The assembler program performs the following operations: + +Defines two integers (num1 and num2) in the .data section. +Adds these integers in the .text section using the eax register. +Outputs the result using the print_int function from asm_io.asm. +Code Snippet: + +asm +Copy code +section .data + num1 dd 5 ; First number + num2 dd 10 ; Second number + result dd 0 ; Result placeholder + +section .text + global asm_main + extern print_int ; Provided in asm_io.asm + +asm_main: + mov eax, [num1] ; Load num1 into eax + add eax, [num2] ; Add num2 to eax + mov [result], eax ; Store result + push eax ; Push result to stack + call print_int ; Call the print function + add esp, 4 ; Clean up the stack + ret +C Driver Program: driver.c +The C program interfaces with the assembler function asm_main to execute the operations. + +Code Snippet: + +c +Copy code +#include <stdio.h> + +int __attribute__((cdecl)) asm_main(void); + +int main() { + int ret_status; + ret_status = asm_main(); + return ret_status; +} +Compilation and Execution +Compilation Commands +The following commands were used to compile and link the program: + +bash +Copy code +nasm -f elf task1.asm -o task1.o +nasm -f elf asm_io.asm -o asm_io.o +gcc -m32 -c driver.c -o driver.o +gcc -m32 driver.o task1.o asm_io.o -o task1 +Execution +Run the program with: + +bash +Copy code +./task1 +Expected Output +The program outputs the sum of num1 and num2: + +Copy code +15 \ No newline at end of file diff --git a/src/asm_io.asm b/src/asm_io.asm new file mode 100644 index 0000000000000000000000000000000000000000..ad52628a8c8d8660a16e358d2e282ec49252d599 --- /dev/null +++ b/src/asm_io.asm @@ -0,0 +1,502 @@ +; +; file: asm_io.asm +; Assembly I/O routines +; To assemble for DJGPP +; nasm -f coff -d COFF_TYPE asm_io.asm +; To assemble for Borland C++ 5.x +; nasm -f obj -d OBJ_TYPE asm_io.asm +; To assemble for Microsoft Visual Studio +; nasm -f win32 -d COFF_TYPE asm_io.asm +; To assemble for Linux +; nasm -f elf -d ELF_TYPE asm_io.asm +; To assemble for Watcom +; nasm -f obj -d OBJ_TYPE -d WATCOM asm_io.asm +; IMPORTANT NOTES FOR WATCOM +; The Watcom compiler's C library does not use the +; standard C calling convention. For example, the +; putchar() function gets its argument from the +; the value of EAX, not the stack. + + +%define NL 10 +%define CF_MASK 00000001h +%define PF_MASK 00000004h +%define AF_MASK 00000010h +%define ZF_MASK 00000040h +%define SF_MASK 00000080h +%define DF_MASK 00000400h +%define OF_MASK 00000800h + + +; +; Linux C doesn't put underscores on labels +; +; %ifdef ELF_TYPE +%define _scanf scanf +%define _printf printf +%define _getchar getchar +%define _putchar putchar +; %endif + +; ; +; ; Watcom puts underscores at end of label +; ; +; %ifdef WATCOM +; %define _scanf scanf_ +; %define _printf printf +; %define _getchar getchar_ +; %define _putchar putchar_ +; %endif + +%ifdef OBJ_TYPE +segment .data public align=4 class=data use32 +%else +segment .data +%endif + +int_format db "%i", 0 +string_format db "%s", 0 +reg_format db "Register Dump # %d", NL + db "EAX = %.8X EBX = %.8X ECX = %.8X EDX = %.8X", NL + db "ESI = %.8X EDI = %.8X EBP = %.8X ESP = %.8X", NL + db "EIP = %.8X FLAGS = %.4X %s %s %s %s %s %s %s", NL + db 0 +carry_flag db "CF", 0 +zero_flag db "ZF", 0 +sign_flag db "SF", 0 +parity_flag db "PF", 0 +overflow_flag db "OF", 0 +dir_flag db "DF", 0 +aux_carry_flag db "AF", 0 +unset_flag db " ", 0 +mem_format1 db "Memory Dump # %d Address = %.8X", NL, 0 +mem_format2 db "%.8X ", 0 +mem_format3 db "%.2X ", 0 +stack_format db "Stack Dump # %d", NL + db "EBP = %.8X ESP = %.8X", NL, 0 +stack_line_format db "%+4d %.8X %.8X", NL, 0 +math_format1 db "Math Coprocessor Dump # %d Control Word = %.4X" + db " Status Word = %.4X", NL, 0 +valid_st_format db "ST%d: %.10g", NL, 0 +invalid_st_format db "ST%d: Invalid ST", NL, 0 +empty_st_format db "ST%d: Empty", NL, 0 + +; +; code is put in the _TEXT segment +; +%ifdef OBJ_TYPE +segment text public align=1 class=code use32 +%else +segment .text +%endif + global read_int, print_int, print_string, read_char + global print_char, print_nl, sub_dump_regs, sub_dump_mem + global sub_dump_math, sub_dump_stack + extern _scanf, _printf, _getchar, _putchar + +read_int: + enter 4,0 + pusha + pushf + + lea eax, [ebp-4] + push eax + push dword int_format + call _scanf + pop ecx + pop ecx + + popf + popa + mov eax, [ebp-4] + leave + ret + +print_int: + enter 0,0 + pusha + pushf + + push eax + push dword int_format + call _printf + pop ecx + pop ecx + + popf + popa + leave + ret + +print_string: + enter 0,0 + pusha + pushf + + push eax + push dword string_format + call _printf + pop ecx + pop ecx + + popf + popa + leave + ret + +read_char: + enter 4,0 + pusha + pushf + + call _getchar + mov [ebp-4], eax + + popf + popa + mov eax, [ebp-4] + leave + ret + +print_char: + enter 0,0 + pusha + pushf + +%ifndef WATCOM + push eax +%endif + call _putchar +%ifndef WATCOM + pop ecx +%endif + + popf + popa + leave + ret + + +print_nl: + enter 0,0 + pusha + pushf + +%ifdef WATCOM + mov eax, 10 ; WATCOM doesn't use the stack here +%else + push dword 10 ; 10 == ASCII code for \n +%endif + call _putchar +%ifndef WATCOM + pop ecx +%endif + popf + popa + leave + ret + + +sub_dump_regs: + enter 4,0 + pusha + pushf + mov eax, [esp] ; read FLAGS back off stack + mov [ebp-4], eax ; save flags + +; +; show which FLAGS are set +; + test eax, CF_MASK + jz cf_off + mov eax, carry_flag + jmp short push_cf +cf_off: + mov eax, unset_flag +push_cf: + push eax + + test dword [ebp-4], PF_MASK + jz pf_off + mov eax, parity_flag + jmp short push_pf +pf_off: + mov eax, unset_flag +push_pf: + push eax + + test dword [ebp-4], AF_MASK + jz af_off + mov eax, aux_carry_flag + jmp short push_af +af_off: + mov eax, unset_flag +push_af: + push eax + + test dword [ebp-4], ZF_MASK + jz zf_off + mov eax, zero_flag + jmp short push_zf +zf_off: + mov eax, unset_flag +push_zf: + push eax + + test dword [ebp-4], SF_MASK + jz sf_off + mov eax, sign_flag + jmp short push_sf +sf_off: + mov eax, unset_flag +push_sf: + push eax + + test dword [ebp-4], DF_MASK + jz df_off + mov eax, dir_flag + jmp short push_df +df_off: + mov eax, unset_flag +push_df: + push eax + + test dword [ebp-4], OF_MASK + jz of_off + mov eax, overflow_flag + jmp short push_of +of_off: + mov eax, unset_flag +push_of: + push eax + + push dword [ebp-4] ; FLAGS + mov eax, [ebp+4] + sub eax, 10 ; EIP on stack is 10 bytes ahead of orig + push eax ; EIP + lea eax, [ebp+12] + push eax ; original ESP + push dword [ebp] ; original EBP + push edi + push esi + push edx + push ecx + push ebx + push dword [ebp-8] ; original EAX + push dword [ebp+8] ; # of dump + push dword reg_format + call _printf + add esp, 76 + popf + popa + leave + ret 4 + +sub_dump_stack: + enter 0,0 + pusha + pushf + + lea eax, [ebp+20] + push eax ; original ESP + push dword [ebp] ; original EBP + push dword [ebp+8] ; # of dump + push dword stack_format + call _printf + add esp, 16 + + mov ebx, [ebp] ; ebx = original ebp + mov eax, [ebp+16] ; eax = # dwords above ebp + shl eax, 2 ; eax *= 4 + add ebx, eax ; ebx = & highest dword in stack to display + mov edx, [ebp+16] + mov ecx, edx + add ecx, [ebp+12] + inc ecx ; ecx = # of dwords to display + +stack_line_loop: + push edx + push ecx ; save ecx & edx + + push dword [ebx] ; value on stack + push ebx ; address of value on stack + mov eax, edx + sal eax, 2 ; eax = 4*edx + push eax ; offset from ebp + push dword stack_line_format + call _printf + add esp, 16 + + pop ecx + pop edx + + sub ebx, 4 + dec edx + loop stack_line_loop + + popf + popa + leave + ret 12 + + +sub_dump_mem: + enter 0,0 + pusha + pushf + + push dword [ebp+12] + push dword [ebp+16] + push dword mem_format1 + call _printf + add esp, 12 + mov esi, [ebp+12] ; address + and esi, 0FFFFFFF0h ; move to start of paragraph + mov ecx, [ebp+8] + inc ecx +mem_outer_loop: + push ecx + push esi + push dword mem_format2 + call _printf + add esp, 8 + + xor ebx, ebx +mem_hex_loop: + xor eax, eax + mov al, [esi + ebx] + push eax + push dword mem_format3 + call _printf + add esp, 8 + inc ebx + cmp ebx, 16 + jl mem_hex_loop + + mov eax, '"' + call print_char + xor ebx, ebx +mem_char_loop: + xor eax, eax + mov al, [esi+ebx] + cmp al, 32 + jl non_printable + cmp al, 126 + jg non_printable + jmp short mem_char_loop_continue +non_printable: + mov eax, '?' +mem_char_loop_continue: + call print_char + + inc ebx + cmp ebx, 16 + jl mem_char_loop + + mov eax, '"' + call print_char + call print_nl + + add esi, 16 + pop ecx + loop mem_outer_loop + + popf + popa + leave + ret 12 + +; function sub_dump_math +; prints out state of math coprocessor without modifying the coprocessor +; or regular processor state +; Parameters: +; dump number - dword at [ebp+8] +; Local variables: +; ebp-108 start of fsave buffer +; ebp-116 temp double +; Notes: This procedure uses the Pascal convention. +; fsave buffer structure: +; ebp-108 control word +; ebp-104 status word +; ebp-100 tag word +; ebp-80 ST0 +; ebp-70 ST1 +; ebp-60 ST2 ... +; ebp-10 ST7 +; +sub_dump_math: + enter 116,0 + pusha + pushf + + fsave [ebp-108] ; save coprocessor state to memory + mov eax, [ebp-104] ; status word + and eax, 0FFFFh + push eax + mov eax, [ebp-108] ; control word + and eax, 0FFFFh + push eax + push dword [ebp+8] + push dword math_format1 + call _printf + add esp, 16 +; +; rotate tag word so that tags in same order as numbers are +; in the stack +; + mov cx, [ebp-104] ; ax = status word + shr cx, 11 + and cx, 7 ; cl = physical state of number on stack top + mov bx, [ebp-100] ; bx = tag word + shl cl,1 ; cl *= 2 + ror bx, cl ; move top of stack tag to lowest bits + + mov edi, 0 ; edi = stack number of number + lea esi, [ebp-80] ; esi = address of ST0 + mov ecx, 8 ; ecx = loop counter +tag_loop: + push ecx + mov ax, 3 + and ax, bx ; ax = current tag + or ax, ax ; 00 -> valid number + je valid_st + cmp ax, 1 ; 01 -> zero + je zero_st + cmp ax, 2 ; 10 -> invalid number + je invalid_st + push edi ; 11 -> empty + push dword empty_st_format + call _printf + add esp, 8 + jmp short cont_tag_loop +zero_st: + fldz + jmp short print_real +valid_st: + fld tword [esi] +print_real: + fstp qword [ebp-116] + push dword [ebp-112] + push dword [ebp-116] + push edi + push dword valid_st_format + call _printf + add esp, 16 + jmp short cont_tag_loop +invalid_st: + push edi + push dword invalid_st_format + call _printf + add esp, 8 +cont_tag_loop: + ror bx, 2 ; mov next tag into lowest bits + inc edi + add esi, 10 ; mov to next number on stack + pop ecx + loop tag_loop + + frstor [ebp-108] ; restore coprocessor state + popf + popa + leave + ret 4 diff --git a/src/asm_io.inc b/src/asm_io.inc new file mode 100644 index 0000000000000000000000000000000000000000..9163be3955bb418e8b5d74d9004b38cc45f7cfa4 --- /dev/null +++ b/src/asm_io.inc @@ -0,0 +1,30 @@ + extern read_int, print_int, print_string + extern read_char, print_char, print_nl + extern sub_dump_regs, sub_dump_mem, sub_dump_math, sub_dump_stack + +%macro dump_regs 1 + push dword %1 + call sub_dump_regs +%endmacro + + +; +; usage: dump_mem label, start-address, # paragraphs +%macro dump_mem 3 + push dword %1 + push dword %2 + push dword %3 + call sub_dump_mem +%endmacro + +%macro dump_math 1 + push dword %1 + call sub_dump_math +%endmacro + +%macro dump_stack 3 + push dword %3 + push dword %2 + push dword %1 + call sub_dump_stack +%endmacro \ No newline at end of file diff --git a/src/driver.c b/src/driver.c new file mode 100644 index 0000000000000000000000000000000000000000..93afaf9597bb78f9a097f12a8faec6767a61d92d --- /dev/null +++ b/src/driver.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int __attribute__((cdecl)) asm_main(void); + +int main() { + int ret_status; + ret_status = asm_main(); + return ret_status; +} diff --git a/src/task1.asm b/src/task1.asm new file mode 100644 index 0000000000000000000000000000000000000000..afd1275137a764d6416eb048fb940ff9ed57393d --- /dev/null +++ b/src/task1.asm @@ -0,0 +1,18 @@ +; task1.asm +section .data + num1 dd 5 ; First number + num2 dd 10 ; Second number + result dd 0 ; Result placeholder + +section .text + global asm_main + extern print_int ; Provided in asm_io.asm + +asm_main: + mov eax, [num1] ; Load num1 into eax + add eax, [num2] ; Add num2 to eax + mov [result], eax ; Store result + push eax ; Push result to stack + call print_int ; Call the print function + add esp, 4 ; Clean up the stack + ret diff --git a/src/task2.asm b/src/task2.asm new file mode 100644 index 0000000000000000000000000000000000000000..9fe5da823bc94c6d5debb4ff10b090afe163ce3a --- /dev/null +++ b/src/task2.asm @@ -0,0 +1,75 @@ +%include "asm_io.inc" + +segment .data +msg1 db "Hello,please enter your name: ", 0 +msg2 db "Enter how many times you want your name to be printed(50-100)", 0 +welcome_msg db "Welcome, ", 0 + error_msg db "Invalid input. Please enter a number between 50 and 100.", 0 + + +section .bss + name resb 100 ; reserve space for the name + num resd 10 ; reserve space for the number + +segment .text +global asm_main +asm_main: + + +pusha + ; Print message for user's name +mov eax, msg1 +call print_string +call print_nl + + +; Read name + mov eax, 3 + mov ebx, 0 + mov ecx, name + mov edx, 100 + int 0x80 + call print_nl ; Add newline after user input + + + ; Print message for second integer +prmopt_num: + mov eax, msg2 + call print_string + call read_int + mov [num], eax + + ; Check value + cmp eax, 50 + jle error + cmp eax, 100 + jg error + + ; Move the input number to a loop counter + mov ecx, eax + +; print_name + print_name: + mov eax, welcome_msg + call print_string + mov eax, name + call print_string + call print_nl + dec ecx ; Decrement counter for loop + cmp ecx, 0 ; Check if loop count is zero + jne print_name ; Jump back to loop if not zero + jmp exit + + + exit: + popa + ret + + +error: + mov eax, 4 + mov ebx, 1 + mov ecx, error_msg + mov edx, 53 ; Length of the error message + int 0x80 ; Print error message + jmp prmopt_num ; Jump back to the second prompt after error \ No newline at end of file