-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
x86-64-assembly/basics: add solution
- Loading branch information
1 parent
d8b908e
commit 8173027
Showing
11 changed files
with
302 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"blurb": "Learn about the basics of x86-64 assembly by following a lasagna recipe.", | ||
"authors": ["bergjohan"], | ||
"forked_from": ["csharp/lucians-luscious-lasagna"], | ||
"files": { | ||
"solution": ["basics.asm"], | ||
"test": ["basics_test.c"], | ||
"exemplar": [".meta/exemplar.asm"] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"track":"x86-64-assembly","exercise":"basics","id":"8c7660921c3a498b87f85737ac342f82","url":"https://exercism.org/tracks/x86-64-assembly/exercises/basics","handle":"ErikSchierboom","is_requester":true,"auto_approve":false} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# Help | ||
|
||
## Running the tests | ||
|
||
To run the tests, execute the following command: | ||
|
||
```bash | ||
make | ||
``` | ||
|
||
## Skipped tests | ||
|
||
Solving an exercise means making all its tests pass. By default, only one test | ||
(the first one) is executed when you run the tests. This is intentional, as it | ||
allows you to focus on just making that one test pass. Once it passes, you can | ||
enable the next test by removing the `TEST_IGNORE()` line. When all tests have | ||
been enabled and your implementation makes them all pass, you'll have solved | ||
the exercise! | ||
|
||
## Submitting your solution | ||
|
||
You can submit your solution using the `exercism submit basics.asm` command. | ||
This command will upload your solution to the Exercism website and print the solution page's URL. | ||
|
||
It's possible to submit an incomplete solution which allows you to: | ||
|
||
- See how others have completed the exercise | ||
- Request help from a mentor | ||
|
||
## Need to get help? | ||
|
||
If you'd like help solving the exercise, check the following pages: | ||
|
||
- The [x86-64 Assembly track's documentation](https://exercism.org/docs/tracks/x86-64-assembly) | ||
- The [x86-64 Assembly track's programming category on the forum](https://forum.exercism.org/c/programming/x86-64-assembly) | ||
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) | ||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) | ||
|
||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. | ||
|
||
To get help if you're having trouble, you can use one of the following resources: | ||
|
||
- [The NASM Manual](https://www.nasm.us/doc/) | ||
- [x86 and amd64 instruction reference](https://www.felixcloutier.com/x86/) | ||
- [StackOverflow](http://stackoverflow.com) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Hints | ||
|
||
## General | ||
|
||
- You need to make the functions [visible to other files][global]. | ||
- The [NASM documentation][interfacing] describes how function arguments are passed and return values are retrieved. | ||
|
||
## 1. Define the expected oven time in minutes | ||
|
||
- There is an [instruction][mov] to store a value in a register. | ||
|
||
## 2. Calculate the remaining oven time in minutes | ||
|
||
- There is an [instruction][sub] for subtracting values. | ||
|
||
## 3. Calculate the preparation time in minutes | ||
|
||
- There is an [instruction][imul] for multiplying values. | ||
|
||
## 4. Calculate the elapsed time in minutes | ||
|
||
- You can [call][call] one of the other functions you've defined previously. | ||
- There is an [instruction][add] for adding values. | ||
|
||
[global]: https://www.nasm.us/xdoc/2.15.02/html/nasmdoc7.html#section-7.7 | ||
[interfacing]: https://www.nasm.us/xdoc/2.15.02/html/nasmdo12.html#section-12.3 | ||
[mov]: https://www.felixcloutier.com/x86/mov | ||
[sub]: https://www.felixcloutier.com/x86/sub | ||
[imul]: https://www.felixcloutier.com/x86/imul | ||
[call]: https://www.felixcloutier.com/x86/call | ||
[add]: https://www.felixcloutier.com/x86/add |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
AS = nasm | ||
|
||
CFLAGS = -g -Wall -Wextra -pedantic -Werror | ||
LDFLAGS = | ||
ASFLAGS = -g -F dwarf -Werror | ||
|
||
ifeq ($(shell uname -s),Darwin) | ||
ifeq ($(shell sysctl -n hw.optional.arm64 2>/dev/null),1) | ||
ALL_CFLAGS = -target x86_64-apple-darwin | ||
endif | ||
ALL_LDFLAGS = -Wl,-pie -Wl,-fatal_warnings | ||
ALL_ASFLAGS = -f macho64 --prefix _ | ||
else | ||
ALL_LDFLAGS = -pie -Wl,--fatal-warnings | ||
ALL_ASFLAGS = -f elf64 | ||
endif | ||
|
||
ALL_CFLAGS += -std=c99 -fPIE -m64 $(CFLAGS) | ||
ALL_LDFLAGS += $(LDFLAGS) | ||
ALL_ASFLAGS += $(ASFLAGS) | ||
|
||
C_OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) | ||
AS_OBJS = $(patsubst %.asm,%.o,$(wildcard *.asm)) | ||
ALL_OBJS = $(C_OBJS) $(AS_OBJS) | ||
|
||
CC_CMD = $(CC) $(ALL_CFLAGS) -c -o $@ $< | ||
|
||
all: tests | ||
@./$< | ||
|
||
tests: $(ALL_OBJS) | ||
@$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $(ALL_OBJS) | ||
|
||
%.o: %.asm | ||
@$(AS) $(ALL_ASFLAGS) -o $@ $< | ||
|
||
%.o: %.c | ||
@$(CC_CMD) | ||
|
||
clean: | ||
@rm -f *.o tests | ||
|
||
.PHONY: all clean |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
# Basics | ||
|
||
Welcome to Basics on Exercism's x86-64 Assembly Track. | ||
If you need help running the tests or submitting your code, check out `HELP.md`. | ||
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) | ||
|
||
## Introduction | ||
|
||
x86-64 assembly is a low-level language. In assembly there are no variables, | ||
instead we use registers to store values. Some registers have a special purpose | ||
such as returning a value from a function, or passing function arguments. To | ||
store a value in a register, we use the `mov` instruction: | ||
|
||
```nasm | ||
mov rax, 42 ; rax = 42 | ||
``` | ||
|
||
An assembly program is divided into sections. The text section holds the | ||
executable instructions of a program and is declared as follows: | ||
|
||
```nasm | ||
section .text | ||
``` | ||
|
||
A function is a set of instructions that perform a specific task. A function | ||
declaration consists of a label with the name of the function, the instructions | ||
that define the function, and the return instruction. The following declares a | ||
function called `foo`, which returns the value 42: | ||
|
||
```nasm | ||
foo: | ||
mov rax, 42 | ||
ret | ||
``` | ||
|
||
The value in the `rax` register specifies the value returned by the function. | ||
|
||
To change the visibility of a function, and be able to call it from any file in | ||
our program we use the `global` directive: | ||
|
||
```nasm | ||
global foo | ||
``` | ||
|
||
When a function is called, the first argument is stored in the `rdi` register, | ||
and the second argument is stored in the `rsi` register. Here's an example of a | ||
function that takes a single argument and returns it, also known as an identity | ||
function: | ||
|
||
```nasm | ||
global identity | ||
identity: | ||
mov rax, rdi | ||
ret | ||
``` | ||
|
||
For the arithmetic operations addition, subtraction, and multiplication, we can | ||
use the `add`, `sub`, and `imul` instructions. They take two operands, a source | ||
operand (first operand), and a destination operand (second operand), performs | ||
the arithmetic operation, and stores the result in the destination operand. | ||
Here's an example of a function that takes two arguments, adds them together, | ||
and returns the result: | ||
|
||
```nasm | ||
global sum | ||
sum: | ||
mov rax, rdi | ||
add rax, rsi ; rax += rsi | ||
ret | ||
``` | ||
|
||
To call a function, we use the `call` instruction. For example, to call our | ||
`sum` function with the arguments 3 and 5, we would do the following: | ||
|
||
```nasm | ||
mov rdi, 3 ; First argument in rdi | ||
mov rsi, 5 ; Second argument in rsi | ||
call sum | ||
; The rax register now contains the value 8 | ||
``` | ||
|
||
## Instructions | ||
|
||
In this exercise you're going to write some code to help you cook a brilliant lasagna from your favorite cooking book. | ||
|
||
You have four tasks, all related to the time spent cooking the lasagna. | ||
|
||
## 1. Define the expected oven time in minutes | ||
|
||
Define the `expected_minutes_in_oven()` function that does not take any parameters and returns how many minutes the lasagna should be in the oven. According to the cooking book, the expected oven time in minutes is 40: | ||
|
||
```c | ||
expected_minutes_in_oven(); | ||
// => 40 | ||
``` | ||
|
||
## 2. Calculate the remaining oven time in minutes | ||
|
||
Define the `remaining_minutes_in_oven()` function that takes the actual minutes the lasagna has been in the oven as a parameter and returns how many minutes the lasagna still has to remain in the oven, based on the expected oven time in minutes from the previous task. | ||
|
||
```c | ||
remaining_minutes_in_oven(30); | ||
// => 10 | ||
``` | ||
## 3. Calculate the preparation time in minutes | ||
Define the `preparation_time_in_minutes()` function that takes the number of layers you added to the lasagna as a parameter and returns how many minutes you spent preparing the lasagna, assuming each layer takes you 2 minutes to prepare. | ||
```c | ||
preparation_time_in_minutes(2); | ||
// => 4 | ||
``` | ||
|
||
## 4. Calculate the elapsed time in minutes | ||
|
||
Define the `elapsed_time_in_minutes()` function that takes two parameters: the first parameter is the number of layers you added to the lasagna, and the second parameter is the number of minutes the lasagna has been in the oven. The function should return how many minutes you've worked on cooking the lasagna, which is the sum of the preparation time in minutes, and the time in minutes the lasagna has spent in the oven at the moment. | ||
|
||
```c | ||
elapsed_time_in_minutes(3, 20); | ||
// => 26 | ||
``` | ||
## Source | ||
### Created by | ||
- @bergjohan |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
section .text | ||
|
||
global expected_minutes_in_oven | ||
expected_minutes_in_oven: | ||
mov rax, 40 | ||
ret | ||
|
||
global remaining_minutes_in_oven | ||
remaining_minutes_in_oven: | ||
call expected_minutes_in_oven | ||
sub rax, rdi | ||
ret | ||
|
||
global preparation_time_in_minutes | ||
preparation_time_in_minutes: | ||
mov rax, rdi | ||
imul rax, 2 | ||
ret | ||
|
||
global elapsed_time_in_minutes | ||
elapsed_time_in_minutes: | ||
call preparation_time_in_minutes | ||
add rax, rsi | ||
ret | ||
|
||
%ifidn __OUTPUT_FORMAT__,elf64 | ||
section .note.GNU-stack noalloc noexec nowrite progbits | ||
%endif |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#include <assert.h> | ||
#include <inttypes.h> | ||
|
||
int64_t expected_minutes_in_oven(void); | ||
int64_t remaining_minutes_in_oven(int64_t actual_minutes_in_oven); | ||
int64_t preparation_time_in_minutes(int64_t number_of_layers); | ||
int64_t elapsed_time_in_minutes(int64_t number_of_layers, int64_t actual_minutes_in_oven); | ||
|
||
int main(void) { | ||
assert(40 == expected_minutes_in_oven()); | ||
assert(15 == remaining_minutes_in_oven(25)); | ||
assert(2 == preparation_time_in_minutes(1)); | ||
assert(8 == preparation_time_in_minutes(4)); | ||
assert(32 == elapsed_time_in_minutes(1, 30)); | ||
assert(16 == elapsed_time_in_minutes(4, 8)); | ||
} |
Binary file not shown.
Binary file not shown.