Skip to content

Commit

Permalink
feat: implement ft_strcpy and its explanation
Browse files Browse the repository at this point in the history
  • Loading branch information
leogaudin committed Jul 23, 2024
1 parent 1c840bb commit a7a12c7
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 8 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ NC = \033[0m
NAME = libasm.a

SOURCES = ft_strlen.s \
# ft_strcpy.s \
ft_strcpy.s \
# ft_strcmp.s \
# ft_write.s \
# ft_read.s \
Expand Down
60 changes: 60 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,63 @@ end:
```

And that's it! We have implemented the `ft_strlen` function in assembly.

## ft_strcpy

The `ft_strcpy` function is a function that copies a string into another string, and returns a pointer to the destination string.

The logic is very similar to the `ft_strlen` function:

1. Set a counter to 0.
2. Look at the first character of the source string.
3. Copy it to the destination string.
4. Increment the counter.
5. Look at the next character and copy it.
6. If it is not the null-terminator, increment the counter and go back to step 5.
7. If it is the null-terminator, exit the loop and return a pointer to the destination string.

### Implementation

A pointer to our `dst` string is passed in `rdi`, and a pointer to our `src` string is passed in `rsi`.

We can start the same way we did with `ft_strlen` by setting the counter to 0.

```nasm
ft_strcpy:
mov rcx, 0
```

We can then start our loop.

We need to copy every character in `rsi` to `rdi`. However, **in assembly, we can't copy data directly from one address to another** (`mov [rdi], [rsi]` would not work).

We therefore need to copy the data from the source address to a register, and then copy it to the destination address.

> We could use any register to store the character (like `r8` as seen before), but it is more appropriate to use `al` for this purpose, as it is a register that is meant to store a single byte.
```nasm
loop:
mov al, [rsi + rcx]
mov [rdi + rcx], al
inc rcx
cmp al, 0
jne loop
```

In this loop:
1. We copy the character in `rsi` to `al`.
2. We copy `al` to `rdi`.
3. We increment the counter.
4. We check if the character is the null-terminator.
5. If it is not, we go back to the beginning of the loop.

Finally, we need to return the pointer to the destination string.

Given that we received this pointer in `rdi` and that we did not move it, we can simply copy it to `rax` and return.

```nasm
mov rax, rdi
ret
```

## ft_strcmp
15 changes: 15 additions & 0 deletions ft_strcpy.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
global _ft_strcpy

_ft_strcpy:
xor rcx, rcx

while:
mov al, [rsi + rcx]
mov [rdi + rcx], al
inc rcx
cmp al, 0
jne while

break:
mov rax, rdi
ret
4 changes: 3 additions & 1 deletion libasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
#define NC "\033[0m"
#define RED "\033[0;31m"
#define GREEN "\033[0;32m"
#define BOLD "\033[1m"

#include <stdio.h>
#include <string.h>

int ft_strlen(char *str);
int ft_strlen(char *str);
char *ft_strcpy(char *dst, char *src);

#endif
43 changes: 37 additions & 6 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

void test_strlen(void)
{
printf("\nTesting ft_strlen\n");
printf(BOLD "\nTesting ft_strlen\n" NC);

char *strings[] = {
"test12345",
Expand All @@ -19,17 +19,48 @@ void test_strlen(void)
int expected = strlen(strings[i]);
int result = ft_strlen(strings[i]);

if (expected == result) {
printf(GREEN "OK" NC);
} else {
printf(RED "KO" NC);
}
printf(expected == result ? GREEN "OK" NC : RED "KO" NC);
printf("\t Expected: %d\tResult: %d\n", expected, result);
}
}

void test_strcpy(void)
{
printf(BOLD "\nTesting ft_strcpy\n" NC);

char *strings[] = {
"test12345",
"1",
"test",
"",
"zzzzzzzz",
};

int numStrings = sizeof(strings) / sizeof(strings[0]);

for (int i = 0; i < numStrings; i++) {
// Test return value
char dummy_dest[100];

void *ref_ptr = strcpy(dummy_dest, strings[i]);
void *test_ptr = ft_strcpy(dummy_dest, strings[i]);
printf(ref_ptr == test_ptr ? GREEN "POINTER OK" NC : RED "POINTER KO" NC);
printf("\tExpected: %p\tResult: %p\n", ref_ptr, test_ptr);

// Test destination string
char ref_dest[100];
char test_dest[100];

strcpy(ref_dest, strings[i]);
ft_strcpy(test_dest, strings[i]);
printf(strcmp(ref_dest, test_dest) == 0 ? GREEN "COPY OK" NC : RED "COPY KO" NC);
printf("\t\tExpected: %s\tResult: %s\n", ref_dest, test_dest);
}
}

int main(void)
{
test_strlen();
test_strcpy();
return (0);
}

0 comments on commit a7a12c7

Please sign in to comment.