Skip to content

Commit

Permalink
stack/functions: Add functions lab.
Browse files Browse the repository at this point in the history
Added functions lab based off old lab material.
Ignored throwback exercise 0.

Signed-off-by: Razvan Miclius <[email protected]>
  • Loading branch information
razvang0307 committed Apr 21, 2024
1 parent d7e7cf8 commit c013973
Show file tree
Hide file tree
Showing 41 changed files with 1,047 additions and 0 deletions.
54 changes: 54 additions & 0 deletions chapters/stack/functions/drills/tasks/print_rev_string/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Displaying the Reversed String

In the file `print_rev_string.asm`, add the `reverse_string` function so that you have a listing similar to the one below:
```Assembly
[...]
section .text
global main
reverse_string:
push ebp
mov ebp, esp
mov eax, dword [ebp+8]
mov ecx, dword [ebp+12]
add eax, ecx
dec eax
mov edx, dword [ebp+16]
copy_one_byte:
mov bl, byte [eax]
mov byte [edx], bl
dec eax
inc edx
loopnz copy_one_byte
inc edx
mov byte [edx], 0
leave
ret
main:
push ebp
mov ebp, esp
[...]
```
> **IMPORTANT:** When copying the `reverse_string` function into your program, remember that the function starts at the `reverse_string` label and ends at the `main` label. The `copy_one_byte` label is part of the `reverse_string` function.
The `reverse_string` function reverses a string and has the following signature: `void reverse_string(const char *src, size_t len, char *dst);`. This means that the first `len` characters of the `src` string are reversed into the `dst` string.

Reverse the `mystring` string into a new string and display that new string.

> **NOTE:** To define a new string, we recommend using the following construction in the data section:
> ```Assembly
> store_string times 64 db 0
> ```
> This creates a string of 64 zero bytes, enough to store the reverse of the string.
> The equivalent C function call is `reverse_string(mystring, ecx, store_string);`. We assume that the length of the string is calculated and stored in the `ecx` register.
>
> You cannot directly use the value of `ecx` in its current form. After the `printf` function call for displaying the length, the value of `ecx` is lost. To retain it, you have two options:
> 1. Store the value of the `ecx` register on the stack beforehand (using `push ecx` before the `printf` call) and then restore it after the `printf` call (using `pop ecx`).
> 2. Store the value of the `ecx` register in a global variable, which you define in the `.data` section.
>
> You cannot use another register because there is a high chance that even that register will be modified by the `printf` call to display the length of the string.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
section .data
mystring db "This is my string", 0
print_format db "String length is %d", 10, 0
store_string times 64 db 0

section .text

extern printf
extern puts
global main

reverse_string:
push ebp
mov ebp, esp

mov eax, dword [ebp+8]
mov ecx, dword [ebp+12]
add eax, ecx
dec eax
mov edx, dword [ebp+16]

copy_one_byte:
mov bl, byte [eax]
mov byte [edx], bl
dec eax
inc edx
loopnz copy_one_byte

inc edx
mov byte [edx], 0

leave
ret

main:
push ebp
mov ebp, esp

mov eax, mystring
xor ecx, ecx
test_one_byte:
mov bl, byte [eax]
test bl, bl
jz out
inc eax
inc ecx
jmp test_one_byte

out:
; save ecx's value since it can be changed by printf
push ecx

push ecx
push print_format
call printf
add esp, 8

pop ecx

push store_string
push ecx
push mystring
call reverse_string
add esp, 12

push store_string
call puts
add esp, 4

leave
ret
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
AS = nasm
CC = gcc
RM = rm

SRCS := $(shell find . -name "*.asm")
OBJS := $(SRCS:.asm=.o)

UTILSDIR := ../utils/

ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)"
CFLAGS ?= -Wall
LDFLAGS ?= -m32 -no-pie

all: print_reverse_string

print_reverse_string_: print_reverse_string.o
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@

%.o: %.asm
$(AS) $(ASFLAGS) $< -o $@

.PHONY: clean

clean:
$(RM) -r *.o print_reverse_string
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
%include "../utils/printf32.asm"

section .data
mystring db "This is my string", 0

section .text

extern puts
extern printf
global main

main:
push ebp
mov ebp, esp

mov eax, mystring
xor ecx, ecx
test_one_byte:
mov bl, byte [eax]
test bl, bl
je out
inc eax
inc ecx
jmp test_one_byte

out:
PRINTF32 `[before]: %s\n[after]: \x0`, mystring

; TODO: print reverse string

leave
ret
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
; SPDX-License-Identifier: BSD-3-Clause

;;; macro to use printf with 32bit parameters:
;;; - 1st parameter MUST be an immediate in backquotes `EAX=%d ECX=%x \n\x0`
;;; escape \n and \x0 only work with backquotes
;;; - rest of parameters MUST be 32bit
;;; - gen purpose and flags are preserved
;;; - stack is cleaned
%macro PRINTF32 1-*
pushf
pushad
jmp %%endstr
%%str: db %1
%%endstr:
%rep %0 - 1
%rotate -1
push dword %1
%endrep
push %%str
call printf
add esp, 4*%0
popad
popf
%endmacro
20 changes: 20 additions & 0 deletions chapters/stack/functions/drills/tasks/rot13/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Bonus: Rot13

Create and use a function that performs [rot13](https://rot13.com/) translation of a string.

## Bonus: Rot13++

Implement `rot13` on an array of strings: the strings are contiguous in memory separated by the string terminator (`NULL`-byte, `0`). For example, `ana\0are\0mere\0` is an array of three strings.

Apply `rot13` to alphabetical characters and replace the string terminator with a space (`' '`, blank, character `32`, or `0x20`). Thus, the initial string `ana\0are\0mere\0` will translate to `nan ner zrer`.

> **NOTE:** To define the array of strings containing the string terminator, use a construction like:
> ```Assembly
> mystring db "ana", 0, "are", 0, "mere", 0
> ```
> **NOTE:** You will need to know when to stop traversing the array of strings. The simplest way is to define a length variable in the `.data` section, like so:
> ```Assembly
> len dd 10
> ```
> where you either store the total length of the string (from the beginning to the last `NULL` byte) or the number of strings in the array.
8 changes: 8 additions & 0 deletions chapters/stack/functions/drills/tasks/string_print/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Displaying a String

To display a string, we can use the internal macro `PRINTF32`. Alternatively, we can use a function such as `puts`. In the file `print_string.asm`, displaying a string using the `PRINTF32` macro is implemented.

Following the example of the `hello_world.asm` file, implement string display using `puts` as well.


If you're having difficulties solving this exercise, take a peek at [hello_world.asm](../../../guides/hello_world/).
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
%include "../utils/printf32.asm"

section .data
mystring db "This is my string", 0

section .text

extern puts
extern printf
global main
main:
push ebp
mov ebp, esp

PRINTF32 `[PRINTF32]: %s\n[PUTS]: \x0`, mystring


push mystring
call puts
add esp, 4

leave
ret
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
AS = nasm
CC = gcc
RM = rm

SRCS := $(shell find . -name "*.asm")
OBJS := $(SRCS:.asm=.o)

UTILSDIR := ../utils/

ASFLAGS ?= -f elf32 -F dwarf -I "$(UTILSDIR)"
CFLAGS ?= -Wall
LDFLAGS ?= -m32 -no-pie

all: print_string

print_string: print_string.o
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@

%.o: %.asm
$(AS) $(ASFLAGS) $< -o $@

.PHONY: clean

clean:
$(RM) -r *.o print_string
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
%include "../utils/printf32.asm"

section .data
mystring db "This is my string", 0

section .text

extern puts
extern printf
global main
main:
push ebp
mov ebp, esp

PRINTF32 `[PRINTF32]: %s\n[PUTS]: \x0`, mystring


; TODO: call puts on string

leave
ret
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
; SPDX-License-Identifier: BSD-3-Clause

;;; macro to use printf with 32bit parameters:
;;; - 1st parameter MUST be an immediate in backquotes `EAX=%d ECX=%x \n\x0`
;;; escape \n and \x0 only work with backquotes
;;; - rest of parameters MUST be 32bit
;;; - gen purpose and flags are preserved
;;; - stack is cleaned
%macro PRINTF32 1-*
pushf
pushad
jmp %%endstr
%%str: db %1
%%endstr:
%rep %0 - 1
%rotate -1
push dword %1
%endrep
push %%str
call printf
add esp, 4*%0
popad
popf
%endmacro
20 changes: 20 additions & 0 deletions chapters/stack/functions/drills/tasks/string_print_len/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Displaying the Length of a String

The program `print_string_len.asm` displays the length of a string using the `PRINTF32` macro. The calculation of the length of the `mystring` string occurs within the program (it is already implemented).

Implement the program to display the length of the string using the `printf` function.

At the end, you will have the length of the string displayed twice: initially with the `PRINTF32` macro and then with the external function call `printf`.

> **NOTE:** Consider that the `printf` call is of the form `printf("String length is %u\n", len);`. You need to construct the stack for this call.
>
> The steps to follow are:
>
> 1. Mark the symbol `printf` as external.
> 2. Define the format string `"String length is %u", 10, 0`.
> 3. Make the function call to `printf`, i.e.:
> 1. Put the two arguments on the stack: the format string and the length.
> 2. Call `printf` using `call`.
> 3. Restore the stack.
>
> The length of the string is found in the `ecx` register.
Loading

0 comments on commit c013973

Please sign in to comment.