diff --git a/ws1/makefile b/ws1/makefile deleted file mode 100644 index 96a76c4deef10c98fc751780b4f998dcff54a9d9..0000000000000000000000000000000000000000 --- a/ws1/makefile +++ /dev/null @@ -1,13 +0,0 @@ -all: task1 - -task1: task1.o asm_io.o driver.o - gcc -m32 -o task1 task1.o asm_io.o driver.o - -task1.o: task1.asm - nasm -f elf task1.asm -o task1.o - -asm_io.o: asm_io.asm - nasm -f elf asm_io.asm -o asm_io.o - -driver.o: driver.c - gcc -m32 -c driver.c -o driver.o diff --git a/ws1/src/Makefile b/ws1/src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4ce6c43638b8448f34dff0946c46619c90f0c7f6 --- /dev/null +++ b/ws1/src/Makefile @@ -0,0 +1,17 @@ +# Makefile for building task2 program from assembly and C in the current directory + +# Target to build task2 executable +task2: driver2.o task2.o asm_io.o + gcc -m32 driver2.o task2.o asm_io.o -o task2 + +# Assemble task2.asm +task2.o: task2.asm + nasm -f elf task2.asm -o task2.o + +# Assemble asm_io.asm +asm_io.o: asm_io.asm + nasm -f elf asm_io.asm -o asm_io.o + +# Compile driver2.c +driver2.o: driver2.c + gcc -m32 -c driver2.c -o driver2.o diff --git a/ws1/src/task2_test/asm_io.asm b/ws1/src/task2_test/asm_io.asm new file mode 100644 index 0000000000000000000000000000000000000000..1fcdaf6689e7abc3d984e2cd98b87176ae7de173 --- /dev/null +++ b/ws1/src/task2_test/asm_io.asm @@ -0,0 +1,503 @@ +; +; 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/ws1/src/task2_test/asm_io.inc b/ws1/src/task2_test/asm_io.inc new file mode 100644 index 0000000000000000000000000000000000000000..9163be3955bb418e8b5d74d9004b38cc45f7cfa4 --- /dev/null +++ b/ws1/src/task2_test/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/ws1/src/task2_test/driver.c b/ws1/src/task2_test/driver.c new file mode 100644 index 0000000000000000000000000000000000000000..1c33ae595b144ddd1cd11b95bf6a6fc53989d4fc --- /dev/null +++ b/ws1/src/task2_test/driver.c @@ -0,0 +1,6 @@ +int __attribute__((cdecl)) asm_main( void ); +int main() { +int ret_status; +ret_status = asm_main(); +return ret_status; +} \ No newline at end of file diff --git a/ws1/src/task2_test/task2.asm b/ws1/src/task2_test/task2.asm new file mode 100644 index 0000000000000000000000000000000000000000..e958ba047c4bd5109195f499c5be4087d4346c42 --- /dev/null +++ b/ws1/src/task2_test/task2.asm @@ -0,0 +1,161 @@ +%include "./asm_io.inc" ; Include I/O library for all I/O operations + +; --- Data Segment --- + +segment .data + welcome_msg db "Hello Thanks for playing - may the ods ever be in your favour, ", 0 ; Welcome message string + prompt_name db "Please enter your Name (mine is Bob): ", 0 ; Prompt message for entering name + prompt_count db "Enter number of times to print (between 50 and 100): ", 0 ; Prompt for number of repetitions + prompt_start db "Enter the start of the range (1 to 100): ", 0 ; Prompt for range start + prompt_end db "Enter the end of the range (1 to 100): ", 0 ; Prompt for range end + range_error_msg db "Error: Invalid range.", 0 ; Error message for invalid range + sum_result_msg db "The sum of numbers in the range is: ", 0 ; Result message for range sum + error_msg db "Error: Number must be between 50 and 100.", 0 ; Error message for invalid count + newline db 10, 0 ; Newline character + +; --- BSS Segment --- + +segment .bss + name resb 30 ; Reserve 30 bytes for storing the user's name + count resd 1 ; Reserve space for storing the count + array resd 100 ; Reserve space for 100 integers + sum resd 1 ; Reserve space for the calculated sum + start_range resd 1 ; Reserve space for the start of the range + end_range resd 1 ; Reserve space for the end of the range + +; --- Code Segment --- + +segment .text + global asm_main ; Make asm_main accessible externally + +asm_main: + pusha ; Save the current state of all general-purpose registers + + ; --- Prompt for entering and reading the user’s name --- + + mov eax, prompt_name ; Load prompt_name address into EAX + call print_string ; Display the name prompt + mov edi, name ; Move address to store the name into EDI + mov ecx, 30 ; Set loop counter to 30 for name input length + xor al, al ; Clear AL for storing characters + +read_name_loop: + call read_char ; Read a character from the user + cmp al, 10 ; Compare with newline character + je name_input_complete ; If newline, finish input + stosb ; Store the character in AL to the memory at EDI + loop read_name_loop ; Repeat for all characters + +name_input_complete: + mov byte [edi], 0 ; Null-terminate the user's inputted name + + ; --- Prompt for entering and reading the count --- + + mov eax, prompt_count ; Load address of prompt_count into EAX + call print_string ; Display the count prompt + call read_int ; Read the integer input + mov [count], eax ; Store the user's inputted count + + ; --- Validating count --- + + mov eax, [count] ; Move count into EAX for validation + cmp eax, 50 ; Compare count with 50 + jl display_error ; Jump to error if less than 50 + cmp eax, 100 ; Compare count with 100 + jg display_error ; Jump to error if greater than 100 + + ; --- Loop for printing the welcome message --- + + mov ecx, eax ; Load count into ECX as loop counter + +print_welcome: + mov eax, welcome_msg ; Load address of welcome_msg into EAX + call print_string ; Print the welcome message + mov eax, name ; Load address of name into EAX + call print_string ; Print the user's name + call print_nl ; Print a newline after each message + loop print_welcome ; Repeat for count times + + ; --- Initialise my array with values from 1 to 100 --- + + mov ecx, 100 ; Set loop counter `ECX` to 100 + mov eax, 1 ; Start with the number 1 + mov ebx, array ; Point `EBX` to the start of the array (index 0) + +initialise_array: + mov [ebx], eax ; Store the value in `EAX` at address `EBX` + inc eax ; Increment `EAX` to the next number + add ebx, 4 ; Move `EBX` 4 bytes forward to the next integer + dec ecx ; Decrement loop counter `ECX` + cmp ecx, 0 ; Check if `ECX` is zero + jne initialise_array ; Repeat until all values are stored + + ; --- Prompt for the range input --- + + mov eax, prompt_start ; Load prompt for start of range into EAX + call print_string ; Display the start range prompt + call read_int ; Read the start range input + mov [start_range], eax ; Store the start of the range + + mov eax, prompt_end ; Load prompt for end of range into EAX + call print_string ; Display the end range prompt + call read_int ; Read the end range input + mov [end_range], eax ; Store the end of the range + + ; --- Validate the range --- + + mov eax, [start_range] ; Load start_range into EAX + cmp eax, 1 ; Ensure start_range is at least 1 + jl range_error ; Jump to error if less than 1 + mov ebx, [end_range] ; Load end_range into EBX + cmp ebx, 100 ; Ensure end_range is at most 100 + jg range_error ; Jump to error if more than 100 + cmp eax, ebx ; Ensure start is less than or equal to end + jg range_error ; Jump to error if invalid range + + ; --- Summing the array within the given range --- + + mov ecx, eax ; Load start_range as starting index into ECX + dec ecx ; Convert to zero-based index + mov ebx, [end_range] ; Load end_range to EBX + sub ebx, eax ; Calculate the range length + inc ebx ; Adjust range to include endpoint + mov edx, 0 ; Initialize sum accumulator in EDX + lea edi, [array] ; Load base address of array into EDI + +sum_array: + add edx, [edi + ecx*4] ; Add current element to sum + inc ecx ; Move to next index + dec ebx ; Decrement range length + jnz sum_array ; Repeat until range is covered + + mov [sum], edx ; Store the calculated sum + + ; --- Display the result of sum within range --- + + mov eax, sum_result_msg ; Load result message into EAX + call print_string ; Display the result message + mov eax, [sum] ; Load calculated sum into EAX + call print_int ; Print the sum + call print_nl ; Print a newline + + ; --- Programme exit point --- + + popa ; Restore original values of registers + ret ; Return from the main function + +display_error: + mov eax, error_msg ; Load error message address + call print_string ; Display error message + call print_nl ; Print newline after error message + jmp exit_programme ; Jump to program exit + +range_error: + mov eax, range_error_msg ; Load range error message address + call print_string ; Display range error message + call print_nl ; Print newline after range error + +exit_programme: + popa ; Restore states of the registers + mov eax, 0 ; Signal successful completion + ret ; Return from the function