diff --git a/README.md b/README.md index ca1f67ca0d360fefddd3649d9e9f9b7eeb78189d..9ec8613be281f1ca5d35f433e2112555d793d196 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,133 @@ -# worksheet1 +# Worksheet 1 +This repository features solutions to assembly programming exercises implemented in x86 assembly language using NASM and GCC. The programs showcase essential concepts in assembly programming, including handling user input, performing calculations, and working with arrays. +--- +## Overview -## Getting started +The repository includes the following programs: -To make it easy for you to get started with GitLab, here's a list of recommended next steps. +**Task 1**: Retrieve two integers from memory, compute their sum, and display the result. +**Task 2**: Accept two integers as input from the user, calculate their sum, and display it. +**Task 3**: Display a welcome message repeatedly based on user-defined input. +**Task 4**: Initialize an array, validate a user-specified range, and compute the sum of elements within that range. -Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! +--- -## Add your files +## Setup Instructions -- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files -- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command: +### Prerequisites +1. Required tools: + - `nasm` (Netwide Assembler) + - `gcc` (GNU Compiler Collection) + - 32-bit compatibility libraries (e.g., `lib32gcc`, `libc6-dev-i386`). -``` -cd existing_repo -git remote add origin https://gitlab.uwe.ac.uk/a2-alluqman/worksheet1.git -git branch -M main -git push -uf origin main -``` +--- -## Integrate with your tools +## Results and Observations -- [ ] [Set up project integrations](https://gitlab.uwe.ac.uk/a2-alluqman/worksheet1/-/settings/integrations) +### Task 1: Sum of Two Integers +**Execution**: +- Successfully compiled and executed. +- Calculated and displayed the sum of two integers predefined in memory. -## Collaborate with your team +**Output**: -- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) -- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) -- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) -- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) -- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html) -## Test and Deploy +**Screenshot**: + -Use the built-in continuous integration in GitLab. -- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html) -- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) -- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) -- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) -- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) +--- -*** +### Task 2: Adding User-Provided Integer Values +**Execution**: +- Asked the user to input two integers, for example, 7 and 41. +- Calculated and displayed their sum (e.g., 48). -# Editing this README + -When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template. +### Task 3: User Welcome Script +**Execution**: +- Checked if the user input for the number of repetitions was within the valid range (50–100). +- Displayed a welcome message when the input was valid. +- Managed invalid inputs effectively with appropriate feedback. -## Suggestions for a good README +**Output Examples**: +**Screenshot**: + -Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. -## Name -Choose a self-explaining name for your project. +--- -## Description -Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. +### Task 4: Setting Up an Array and Computing Range Sum +**Execution**: +- Calculated the sum of an entire array. +- Accepted user input for a range, validated it, and displayed the sum for the specified range. -## Badges -On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. +**Output Examples**: + -## Visuals -Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. +--- -## Installation -Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. +## Build Instructions -## Usage -Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. +### Manual Compilation of Individual Tasks +1. Navigate to the Source Directory +Move to the src folder containing the source files: + ```bash + cd src + ``` +2. Assemble `.asm` Files into Object Files +Use NASM to compile .asm files into object files: + ```bash + nasm -f elf <file>.asm -o ../build/<file>.o + ``` + Example: + ```bash + nasm -f elf task1.asm -o ../build/task1.o + ``` +3. Compile the C Driver File +Build the driver file using GCC: + ```bash + gcc -m32 -c driver.c -o ../build/driver.o + ``` +4. Link Object Files to Create Executables +Combine the object files into an executable (run this from the root directory): + ```bash + gcc -m32 build/driver.o build/<file>.o build/asm_io.o -o <output> + ``` + Example: + ```bash + gcc -m32 build/driver.o build/task1.o build/asm_io.o -o task1 + ``` -## Support -Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. - -## Roadmap -If you have ideas for releases in the future, it is a good idea to list them in the README. - -## Contributing -State if you are open to contributions and what your requirements are for accepting them. - -For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. - -You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. - -## Authors and acknowledgment -Show your appreciation to those who have contributed to the project. - -## License -For open source projects, say how it is licensed. - -## Project status -If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. +--- + +### Build and Run Instructions +**Build All Programs**: +- To compile all programs in one step, execute: + ```bash + make + ``` + +**Cleaning Up**: +- To delete all compiled binaries and object files, run: + ```bash + make clean + ``` + +--- + +## Running the Programs + +### Execution Instructions + +- From the root directory, execute the compiled binaries for each task as follows: + ```bash + ./task1 + ./task2 + ./task3 + ./task4 + ``` +--- diff --git a/src/Makefile b/src/Makefile index 9680dcf59641e756d8bcf44cd836279177af058c..273082e70a0f91c1cd5f4fa138289c20412d5268 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,64 +1,55 @@ -# Makefile for building executables from assembly and C source files - # Compiler and assembler settings -NASM=nasm -GCC=gcc -OBJFLAGS=-m32 -c -ASMFLAGS=-f elf +NASM = nasm +GCC = gcc +NASM_FLAGS = -f elf +GCC_FLAGS = -m32 + +# Directories +SRC_DIR = src +BUILD_DIR = build -# Source files -TASK_1_SRC=task_1.asm -TASK2_SRC=task2.asm -TASK2_1_SRC=task2_1.asm -ASM_IO_SRC=asm_io.asm -DRIVER_SRC=Driver.c +# Targets +TARGETS = task1 task2 task3 task4 # Object files -TASK1_OBJ=task_1.o -TASK2_OBJ=task2.o -TASK2_1_OBJ=task2_1.o # Updated from TASK2B_OBJ to TASK2AA_OBJ -ASM_IO_OBJ=asm_io.o -DRIVER_OBJ=Driver.o +OBJS = $(BUILD_DIR)/task1.o $(BUILD_DIR)/task2.o $(BUILD_DIR)/task3.o $(BUILD_DIR)/task4.o $(BUILD_DIR)/asm_io.o $(BUILD_DIR)/driver.o -# Executable targets -EXECUTABLE_1=task_1 -EXECUTABLE2=task2 -EXECUTABLE2_1=task2_1 +# Default rule: build all targets +all: $(TARGETS) -# Default rule to build all targets -all: $(EXECUTABLE_1) $(EXECUTABLE2) $(EXECUTABLE2_1) +# Rules to build each target +task1: $(BUILD_DIR)/task1.o $(BUILD_DIR)/asm_io.o $(BUILD_DIR)/driver.o + $(GCC) $(GCC_FLAGS) $(BUILD_DIR)/driver.o $(BUILD_DIR)/task1.o $(BUILD_DIR)/asm_io.o -o task1 -# Rule to link the executable for task1 -$(EXECUTABLE1): $(DRIVER_OBJ) $(TASK1_OBJ) $(ASM_IO_OBJ) - $(GCC) -m32 $(DRIVER_OBJ) $(TASK1_OBJ) $(ASM_IO_OBJ) -o $(EXECUTABLE_1) +task2: $(BUILD_DIR)/task2.o $(BUILD_DIR)/asm_io.o $(BUILD_DIR)/driver.o + $(GCC) $(GCC_FLAGS) $(BUILD_DIR)/driver.o $(BUILD_DIR)/task2.o $(BUILD_DIR)/asm_io.o -o task2 -# Rule to link the executable for task2A -$(EXECUTABLE2A): $(DRIVER_OBJ) $(TASK2A_OBJ) $(ASM_IO_OBJ) - $(GCC) -m32 $(DRIVER_OBJ) $(TASK2A_OBJ) $(ASM_IO_OBJ) -o $(EXECUTABLE2) +task3: $(BUILD_DIR)/task3.o $(BUILD_DIR)/asm_io.o $(BUILD_DIR)/driver.o + $(GCC) $(GCC_FLAGS) $(BUILD_DIR)/driver.o $(BUILD_DIR)/task3.o $(BUILD_DIR)/asm_io.o -o task3 -# Rule to link the executable for task2AA -$(EXECUTABLE2): $(DRIVER_OBJ) $(TASK2_OBJ) $(ASM_IO_OBJ) - $(GCC) -m32 $(DRIVER_OBJ) $(TASK2AA_OBJ) $(ASM_IO_OBJ) -o $(EXECUTABLE2_1) +task4: $(BUILD_DIR)/task4.o $(BUILD_DIR)/asm_io.o $(BUILD_DIR)/driver.o + $(GCC) $(GCC_FLAGS) $(BUILD_DIR)/driver.o $(BUILD_DIR)/task4.o $(BUILD_DIR)/asm_io.o -o task4 -# Rules to build object files from assembly sources -$(TASK_1_OBJ): $(TASK_1_SRC) - $(NASM) $(ASMFLAGS) $(TASK1_SRC) -o $(TASK1_OBJ) +# Rules to assemble the .asm files +$(BUILD_DIR)/asm_io.o: $(SRC_DIR)/asm_io.asm + $(NASM) $(NASM_FLAGS) $(SRC_DIR)/asm_io.asm -o $(BUILD_DIR)/asm_io.o -$(TASK2_OBJ): $(TASK2_SRC) - $(NASM) $(ASMFLAGS) $(TASK2_SRC) -o $(TASK2_OBJ) +$(BUILD_DIR)/task1.o: $(SRC_DIR)/task1.asm + $(NASM) $(NASM_FLAGS) $(SRC_DIR)/task1.asm -o $(BUILD_DIR)/task1.o -$(TASK2_!_OBJ): $(TASK2_1_SRC) # Updated from TASK2B_OBJ to TASK2AA_OBJ - $(NASM) $(ASMFLAGS) $(TASK2_1_SRC) -o $(TASK2_1_OBJ) +$(BUILD_DIR)/task2.o: $(SRC_DIR)/task2.asm + $(NASM) $(NASM_FLAGS) $(SRC_DIR)/task2.asm -o $(BUILD_DIR)/task2.o -$(ASM_IO_OBJ): $(ASM_IO_SRC) - $(NASM) $(ASMFLAGS) $(ASM_IO_SRC) -o $(ASM_IO_OBJ) +$(BUILD_DIR)/task3.o: $(SRC_DIR)/task3.asm + $(NASM) $(NASM_FLAGS) $(SRC_DIR)/task3.asm -o $(BUILD_DIR)/task3.o -# Rule to build the object file from the C source -$(DRIVER_OBJ): $(DRIVER_SRC) - $(GCC) $(OBJFLAGS) $(DRIVER_SRC) -o $(DRIVER_OBJ) +$(BUILD_DIR)/task4.o: $(SRC_DIR)/task4.asm + $(NASM) $(NASM_FLAGS) $(SRC_DIR)/task4 -o $(BUILD_DIR)/task4.o -# Clean rule to remove generated files -clean: - rm -f $(TASK1_OBJ) $(TASK2_OBJ) $(TASK2_1_OBJ) $(ASM_IO_OBJ) $(DRIVER_OBJ) $(EXECUTABLE1) $(EXECUTABLE2) $(EXECUTABLE2_1) +# Rule to compile the C driver file +$(BUILD_DIR)/driver.o: $(SRC_DIR)/driver.c + $(GCC) $(GCC_FLAGS) -c $(SRC_DIR)/driver.c -o $(BUILD_DIR)/driver.o -.PHONY: all clean +# Clean rule to remove compiled files +clean: + rm -f $(BUILD_DIR)/*.o $(TARGETS) \ No newline at end of file diff --git a/src/asm_io.asm b/src/asm_io.asm index 96c5e4993668355f44c85af5999d640a41c0ec84..149726dc139378a44b244de53962dd91410a0c24 100644 --- a/src/asm_io.asm +++ b/src/asm_io.asm @@ -1,502 +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 +; +; 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 \ No newline at end of file diff --git a/src/asm_io.inc b/src/asm_io.inc index de719de00811503d00e7a01458f40b2f7931e290..9163be3955bb418e8b5d74d9004b38cc45f7cfa4 100644 --- a/src/asm_io.inc +++ b/src/asm_io.inc @@ -1,30 +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 + 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 +%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 + 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 +%macro dump_math 1 + push dword %1 + call sub_dump_math %endmacro %macro dump_stack 3 -push dword %3 + push dword %3 push dword %2 -push dword %1 + push dword %1 call sub_dump_stack -%endmacro +%endmacro \ No newline at end of file diff --git a/src/Driver.c b/src/driver.c similarity index 62% rename from src/Driver.c rename to src/driver.c index e4e7dd9da6cd226f6e38beffbb371b35631bb06c..a9a2b5b974c2a7260b5ea2198b07a814c12de6f3 100644 --- a/src/Driver.c +++ b/src/driver.c @@ -1,7 +1,8 @@ -int __attribute__((cdecl)) asm_main( void ); - -int main() { - int ret_status; - ret_status = asm_main(); - return ret_status; -} +int __attribute__((cdecl)) asm_main(void); + +int main() { + int ret_status; + ret_status = asm_main(); + return ret_status; +} + diff --git a/src/Driver.o b/src/driver.o similarity index 95% rename from src/Driver.o rename to src/driver.o index 0c90eee477cb0085421234f2286e48f23f37299e..d9c964d5c502ff05525b278dcc90cc8150982da0 100644 Binary files a/src/Driver.o and b/src/driver.o differ diff --git a/src/screenshots/task1.png b/src/screenshots/task1.png new file mode 100644 index 0000000000000000000000000000000000000000..f97815ca57b9f05a0656317b8693fbd2aebc1e51 Binary files /dev/null and b/src/screenshots/task1.png differ diff --git a/src/screenshots/task2.png b/src/screenshots/task2.png new file mode 100644 index 0000000000000000000000000000000000000000..d59fc73119121ba91a6b6052286b1c996997b92e Binary files /dev/null and b/src/screenshots/task2.png differ diff --git a/src/screenshots/task3.png b/src/screenshots/task3.png new file mode 100644 index 0000000000000000000000000000000000000000..fcbd83c2f2de73c7752acfd95b9d2d48d45f14b5 Binary files /dev/null and b/src/screenshots/task3.png differ diff --git a/src/screenshots/task4.png b/src/screenshots/task4.png new file mode 100644 index 0000000000000000000000000000000000000000..f6b6de4b7c97606eefb85158e056e760aecd770f Binary files /dev/null and b/src/screenshots/task4.png differ diff --git a/src/task_1 b/src/task1 similarity index 81% rename from src/task_1 rename to src/task1 index ae332ae7c3b6270aae940c5ffb0007bcb6078f95..1f1d6ecf7da85dee6b0badecddafb093ab59395b 100755 Binary files a/src/task_1 and b/src/task1 differ diff --git a/src/task1.asm b/src/task1.asm new file mode 100644 index 0000000000000000000000000000000000000000..2aec9da3b3cc54a3bd8573776548b0fd135c1f87 --- /dev/null +++ b/src/task1.asm @@ -0,0 +1,24 @@ +%include "asm_io.inc" + +segment .data + integer1 dd 15 ; first integer + integer2 dd 6 ; second integer + +segment .bss + result resd 1 ; variable to store the result + +segment .text + global asm_main ; make the asm_main function callable +asm_main: + pusha ; save all general-purpose registers + + mov eax, [integer1] ; load integer1 into EAX + add eax, [integer2] ; add integer2 to EAX + mov [result], eax ; store the result in the 'result' variable + + call print_int ; print the result using asm_io.inc + + popa ; restore all registers + mov eax, 0 ; set return value to 0 + ret ; return from the function + diff --git a/src/task1.o b/src/task1.o new file mode 100644 index 0000000000000000000000000000000000000000..786e5f26a8d1249dfac2f2ba49e639cd4425358d Binary files /dev/null and b/src/task1.o differ diff --git a/src/task2 b/src/task2 index 8aee5a55e8bd1135d0eeee2b1a025dc34f53676a..6a940f166e80dfa56a9a4adeebefd4cde08f70c0 100755 Binary files a/src/task2 and b/src/task2 differ diff --git a/src/task2.asm b/src/task2.asm index 24dc1cb01af2cc36f2029a54d3107eabb0775fde..e1917400b17649f5092df26efe6d2284be4d2a52 100644 --- a/src/task2.asm +++ b/src/task2.asm @@ -1,101 +1,72 @@ -section .data - welcome_message db 'Welcome to Assembly, ', 0 - too_small_message db 'Error: The number is too small!', 10, 0 - too_large_message db 'Error: The number is too large!', 10, 0 - newline db 10, 0 +%include "asm_io.inc" -section .bss - name resb 32 ; Reserve 32 bytes for the user's name - num resb 4 ; Reserve 4 bytes for the number input by the user - input_value resb 4 +segment .data + prompt db "Enter a number: ", 0 ; Prompt to input a number + sum_msg db "The sum of ", 0 ; Start of the result message + and_msg db " and ", 0 ; Middle part of the result message + result_msg db " is: ", 0 ; End of the result message -section .text - global asm_main +segment .bss + num1 resd 1 ; Space for the first number + num2 resd 1 ; Space for the second number + total resd 1 ; Space for the sum result +segment .text + global asm_main asm_main: - - ; Ask for user's name - mov eax, 4 ; syscall number for sys_write - mov ebx, 1 ; file descriptor 1 = stdout - mov ecx, welcome_message ; address of the message - mov edx, 23 ; length of the message - int 0x80 ; interrupt to execute syscall - - ; Read user's name - mov eax, 3 ; syscall number for sys_read - mov ebx, 0 ; file descriptor 0 = stdin - mov ecx, name ; buffer to store user's name - mov edx, 32 ; max number of bytes to read - int 0x80 ; interrupt to execute syscall - - ; Ask for the number of times to print the message - mov eax, 4 ; syscall number for sys_write - mov ebx, 1 ; file descriptor 1 = stdout - mov ecx, newline ; newline to separate - mov edx, 1 ; length of the newline - int 0x80 ; interrupt to execute syscall - - mov eax, 3 ; syscall number for sys_read - mov ebx, 0 ; file descriptor 0 = stdin - mov ecx, num ; buffer to store the number - mov edx, 4 ; max number of bytes to read - int 0x80 ; interrupt to execute syscall - - ; Convert string input to integer - mov eax, [num] ; load user input into eax - sub eax, '0' ; convert ASCII to integer - - ; Check if number is less than 50 - cmp eax, 50 ; compare number with 50 - jl too_small ; jump to error if number < 50 - - ; Check if number is greater than 100 - cmp eax, 100 ; compare number with 100 - jg too_large ; jump to error if number > 100 - - ; Print welcome message the requested number of times -print_message: - push eax ; save the counter - mov eax, 4 ; syscall number for sys_write - mov ebx, 1 ; file descriptor 1 = stdout - mov ecx, welcome_message ; address of the message - mov edx, 23 ; length of the message - int 0x80 ; interrupt to execute syscall - - ; Print user's name - mov eax, 4 ; syscall number for sys_write - mov ebx, 1 ; file descriptor 1 = stdout - mov ecx, name ; address of the user's name - mov edx, 32 ; length of the user's name - int 0x80 ; interrupt to execute syscall - - ; Restore counter and decrease it - pop eax - dec eax - jnz print_message ; continue if not zero - - jmp exit ; jump to exit - -too_small: - ; Print error message if number < 50 - mov eax, 4 ; syscall number for sys_write - mov ebx, 1 ; file descriptor 1 = stdout - mov ecx, too_small_message ; address of the error message - mov edx, 30 ; length of the message - int 0x80 ; interrupt to execute syscall - jmp exit ; exit - -too_large: - ; Print error message if number > 100 - mov eax, 4 ; syscall number for sys_write - mov ebx, 1 ; file descriptor 1 = stdout - mov ecx, too_large_message ; address of the error message - mov edx, 30 ; length of the message - int 0x80 ; interrupt to execute syscall - jmp exit ; exit - -exit: - ; Exit the program - mov eax, 1 ; syscall number for sys_exit - xor ebx, ebx ; exit code 0 - int 0x80 ; interrupt to execute syscall + pusha ; Save registers + + ; Input first number + call print_prompt + call read_input + mov [num1], eax ; Store the first number + + ; Input second number + call print_prompt + call read_input + mov [num2], eax ; Store the second number + + ; Calculate the sum + call calculate_sum + + ; Display the result + call display_result + + popa ; Restore registers + mov eax, 0 ; Return 0 + ret ; Exit program + +; Function: Print the input prompt +print_prompt: + mov eax, prompt + call print_string ; Display "Enter a number: " + ret + +; Function: Read an integer input +read_input: + call read_int ; Read user input + ret + +; Function: Calculate the sum of num1 and num2 +calculate_sum: + mov eax, [num1] ; Load the first number + add eax, [num2] ; Add the second number + mov [total], eax ; Store the result + ret + +; Function: Display the result message +display_result: + mov eax, sum_msg + call print_string ; Print "The sum of " + mov eax, [num1] + call print_int ; Print the first number + mov eax, and_msg + call print_string ; Print " and " + mov eax, [num2] + call print_int ; Print the second number + mov eax, result_msg + call print_string ; Print " is: " + mov eax, [total] + call print_int ; Print the sum + call print_nl ; Print a newline + ret diff --git a/src/task2.o b/src/task2.o index fe43b81ed0f129ed6b2b2d5d4432bb4962fb4adc..85dbb5b156f8c78fb88b6d91098b2e6d466e0fe0 100644 Binary files a/src/task2.o and b/src/task2.o differ diff --git a/src/task2_1.asm b/src/task2_1.asm deleted file mode 100644 index f10ef1eed988ee20ce32b82c358860bdfa5ea60c..0000000000000000000000000000000000000000 --- a/src/task2_1.asm +++ /dev/null @@ -1,67 +0,0 @@ -%include "asm_io.inc" - -section .data - welcome_msg db "Welcome, ", 0 ; Message to be printed - name_msg db "Enter your name: ", 0 ; Prompt for name - num_msg db "Enter a number between 50 and 100: ", 0 ; Prompt for number - error_msg db "Error: Number must be between 50 and 100!", 0 ; Error message - newline db 10, 0 ; Newline character - -section .bss - name resb 20 ; Reserve space for a 20-character name - num resd 1 ; Reserve space for the input number - count resd 1 ; Reserve space for loop counter - -section .text - global asm_main - -asm_main: - enter 0,0 ; Set up stack frame - pusha ; Save all general-purpose registers - - ; Step 1: Ask for name - mov eax, name_msg - call print_string - ;call read_string ; Read user name into the 'name' buffer - mov eax, name - call print_string ; Print the entered name - - ; Step 2: Ask for number - mov eax, num_msg - call print_string - call read_int ; Read the number from the user into eax - mov [num], eax ; Store the input number in memory - - ; Step 3: Check if number is valid (between 50 and 100) - mov eax, [num] - cmp eax, 50 ; Compare number with 50 - jl print_error ; If number is less than 50, jump to error - cmp eax, 100 ; Compare number with 100 - jg print_error ; If number is greater than 100, jump to error - - ; Step 4: Valid number, print welcome message that many times - mov [count], eax ; Store the input number in count - -print_loop: - mov eax, welcome_msg - call print_string ; Print the welcome message - mov eax, name - call print_string ; Print the user's name - call print_nl ; Print a newline - - ; Decrement counter - dec dword [count] - cmp dword [count], 0 ; If count > 0, loop again - jg print_loop - - jmp end_program ; Exit program - -print_error: - mov eax, error_msg - call print_string ; Print error message - call print_nl ; Print a newline - -end_program: - popa ; Restore all registers - leave ; Clean up stack - ret ; Return to C \ No newline at end of file diff --git a/src/task2_1.o b/src/task2_1.o deleted file mode 100644 index 01aaa8a268aeb4ed44d15f41c5dfac4f4b18cce1..0000000000000000000000000000000000000000 Binary files a/src/task2_1.o and /dev/null differ diff --git a/src/task2_1 b/src/task3 similarity index 57% rename from src/task2_1 rename to src/task3 index cd00511b1885a82997d148913adc04e5d23ddcb6..cf45abd068f219364a4b1981c6a282ca30b0c9f3 100755 Binary files a/src/task2_1 and b/src/task3 differ diff --git a/src/task3.asm b/src/task3.asm new file mode 100644 index 0000000000000000000000000000000000000000..bff4c0daeb4a1a545124e53440708a156ce3feae --- /dev/null +++ b/src/task3.asm @@ -0,0 +1,97 @@ +%include "asm_io.inc" + +segment .data + prompt_name db "Enter your name: ", 0 ; Prompt to enter name + prompt_number db "Enter a number (50-100): ", 0 ; Prompt for number input + greeting db "Hello, ", 0 ; Greeting message prefix + newline_char db 10, 0 ; Newline character + error_large db "Error: Number is too large!", 0 ; Error message for large number + error_small db "Error: Number is too small!", 0 ; Error message for small number + name_buffer db 100, 0 ; Buffer to store user name + success_output db "Here are your messages:", 0 ; Success message + +segment .bss + number resd 1 ; Space for user number + +segment .text + global asm_main +asm_main: + pusha ; Save registers + + ; Prompt and input user name + call get_name + + ; Prompt and input number + call get_number + + ; Validate input number + call validate_number + + ; Display messages if number is valid + mov eax, success_output + call print_string ; Print success message + call print_messages ; Display messages + + jmp program_exit ; Exit program + +number_too_large: + mov eax, error_large + call print_string ; Error for number > 100 + call print_nl + jmp program_exit + +number_too_small: + mov eax, error_small + call print_string ; Error for number < 50 + call print_nl + jmp program_exit + +program_exit: + popa ; Restore registers + mov eax, 0 ; Exit code + ret + +; Function: Get user name +get_name: + mov eax, prompt_name + call print_string ; Prompt for name + mov esi, name_buffer ; Pointer to name buffer +read_char_loop: + call read_char ; Read character + cmp al, 10 ; Check for newline + je end_name_input ; Exit if newline + mov [esi], al ; Store character + inc esi ; Move to next buffer location + jmp read_char_loop +end_name_input: + mov byte [esi], 0 ; Null-terminate string + ret + +; Function: Get user number +get_number: + mov eax, prompt_number + call print_string ; Prompt for number + call read_int ; Read number input + mov [number], eax ; Store number + ret + +; Function: Validate the number +validate_number: + mov eax, [number] + cmp eax, 50 + jl number_too_small ; If number < 50, go to error + cmp eax, 100 + jg number_too_large ; If number > 100, go to error + ret + +; Function: Print welcome messages +print_messages: + mov ecx, [number] ; Load count for loop +message_loop: + mov eax, greeting + call print_string ; Print "Hello, " + mov eax, name_buffer + call print_string ; Print user name + call print_nl ; Print newline + loop message_loop ; Loop until count is zero + ret diff --git a/src/task3.o b/src/task3.o new file mode 100644 index 0000000000000000000000000000000000000000..e23fe52552206690e559abc11f2166473ad9128e Binary files /dev/null and b/src/task3.o differ diff --git a/src/task4 b/src/task4 new file mode 100755 index 0000000000000000000000000000000000000000..be378826cd75edc8e6303582dec502794ee6d406 Binary files /dev/null and b/src/task4 differ diff --git a/src/task4.asm b/src/task4.asm new file mode 100644 index 0000000000000000000000000000000000000000..2bbb07228fcc87598e8c46a621a380c04e42a951 --- /dev/null +++ b/src/task4.asm @@ -0,0 +1,115 @@ +%include "asm_io.inc" + +segment .data + range_prompt db "Enter the range (start and end): ", 0 ; Message to prompt for range + invalid_range_msg db "Error: Enter values between 1 and 100, with start <= end.", 0 ; Range error message + result_msg db "Calculated sum is: ", 0 ; Message to display the sum + +segment .bss + numbers resd 100 ; Array to hold numbers 1 to 100 + range_start resd 1 ; Starting index of the range + range_end resd 1 ; Ending index of the range + calculated_sum resd 1 ; Holds the calculated sum + +segment .text + global asm_main +asm_main: + pusha ; Save registers + + ; Populate array with numbers 1 to 100 + call initialize_array + + ; Prompt and read the range from the user + call get_range + + ; Validate the range + call validate_range + + ; If valid, calculate the sum + call compute_sum + + ; Display the sum + call display_sum + jmp exit_program ; Exit program + +range_invalid: + mov eax, invalid_range_msg + call print_string ; Print invalid range message + call print_nl + jmp exit_program ; Terminate after error + +exit_program: + popa ; Restore registers + mov eax, 0 ; Return 0 + ret + +; Function: Initialize array with values 1 to 100 +initialize_array: + mov ecx, 100 ; Loop counter for 100 elements + mov esi, numbers ; Array base pointer + mov eax, 1 ; Starting value +array_fill_loop: + mov [esi], eax ; Store value in array + add esi, 4 ; Move to the next array element + inc eax ; Increment value + loop array_fill_loop ; Loop through 100 elements + ret + +; Function: Prompt and read range (start and end) +get_range: + mov eax, range_prompt + call print_string ; Prompt for range + call read_int ; Read start index + mov [range_start], eax ; Store start value + call read_int ; Read end index + mov [range_end], eax ; Store end value + ret + +; Function: Validate the user-provided range +validate_range: + mov eax, [range_start] + cmp eax, 1 ; Check if start >= 1 + jl range_invalid + cmp eax, 100 ; Check if start <= 100 + jg range_invalid + mov ebx, [range_end] + cmp ebx, eax ; Check if start <= end + jl range_invalid + cmp ebx, 100 ; Check if end <= 100 + jg range_invalid + ret + +; Function: Calculate the sum of the specified range +compute_sum: + mov esi, numbers ; Base pointer for array + mov eax, [range_start] + dec eax ; Convert to zero-based index + mov edi, [range_end] + dec edi ; Convert to zero-based index + + mov ecx, edi ; Calculate number of elements + sub ecx, eax + inc ecx ; Include last element + + ; Adjust base pointer to the start of the range + shl eax, 2 ; Scale start index by 4 (size of int) + add esi, eax ; Adjust pointer to range start + + xor edx, edx ; Clear sum accumulator +sum_calculation_loop: + mov ebx, [esi] ; Load value from array + add edx, ebx ; Add to sum + add esi, 4 ; Move to next element + loop sum_calculation_loop ; Loop through the range + + mov [calculated_sum], edx ; Store the sum + ret + +; Function: Display the calculated sum +display_sum: + mov eax, result_msg + call print_string ; Print result message + mov eax, [calculated_sum] + call print_int ; Print the sum + call print_nl ; Print newline + ret diff --git a/src/task4.o b/src/task4.o new file mode 100644 index 0000000000000000000000000000000000000000..dee74ee2235c9b7cd2f8c8e6f2b12f64384d9508 Binary files /dev/null and b/src/task4.o differ diff --git a/src/task_1.asm b/src/task_1.asm deleted file mode 100644 index 8cf2217ef680299fa111b6f896ceaad277ee998c..0000000000000000000000000000000000000000 --- a/src/task_1.asm +++ /dev/null @@ -1,16 +0,0 @@ -%include "asm_io.inc" -segment .data -integer1 dd 15 ; first int - integer2 dd 6 ; second int -segment .bss -result resd 1 ; result -segment .text -global asm_main -asm_main: -pusha -mov eax, [integer1] ; eax = int1 -add eax, [integer2] ; eax = int1 + int2 -mov [result], eax ; result = int1 + int2 -call print_int ; print result - popa -mov eax, 0 \ No newline at end of file diff --git a/src/task_1.o b/src/task_1.o deleted file mode 100644 index 20cbee47a4492946eecdaeda907e0318046c13e0..0000000000000000000000000000000000000000 Binary files a/src/task_1.o and /dev/null differ