Implement the following functions in x86 assembly:
- strlen
- strchr
- memcpy
- memset
- strcmp
- strset
Here is the C prototype for strlen:
size_t strlen(const char *str);
This function returns the number of characters found before the null-byte character in a C-string. We can set AL to null and loop over EDI using REPNE SCASB. We will set ECX to -1 to begin, and then NOT the bytes and subtract by 1 to get the positive number length result.
_strlen: push edi mov edi, [esp + 0x8] ; char *str xor eax, eax ; al = '\0' xor ecx, ecx ; ecx = -1 not ecx cld repne scasb not ecx ; correct ecx lea eax, [ecx - 0x1] pop edi ret
Here is the C prototype for strchr:
char *strchr(char *str, int character);
The method of searching in the strchr function seems like it would be very similar to strlen. The are two main differences. Instead of searching for the null byte, we are searching for a user passed argument. And instead of returning the length, we return a pointer to the first time the search character is found.
We could be naive and just change some code in strlen, but looping with REPNE here means we could overrun the string buffer into unknown memory space. We need logic to check for the null byte as well, making the function more complicated. We could implement a strlen lookup beforehand, but it is more efficient to revert to more generic looping and comparison constructs.
_strchr: mov eax, [esp + 0x4] ; char *str mov ecx, [esp + 0x8] ; char c chr_loop: mov dl, [eax] ; edx is caller-saved cmp cl, dl ; *eax == c je chr_leave inc eax test dl, dl ; check '\0' jnz chr_loop xor eax, eax ; nullptr on fail chr_leave: ret
Here is the C prototype for memcpy:
void *memcpy (void *destination, const void *source, size_t num);
This implementation is very convenient in x86. We use the REP MOVSB operation, which will copy ESI to EDI byte by byte until ECX reaches 0.
_memcpy: push edi ; non-volatiles push esi mov edi, [esp + 0xc] ; void *dest mov esi, [esp + 0x10] ; const void *src mov ecx, [esp + 0x14] ; size_t num mov eax, edi ; return dest cld ; DF = 0 (++) rep movsb ; ends at ecx = 0 pop esi pop edi ret
Here is the C prototype for memset:
void *memset (void *ptr, int value, size_t num);
This implementation is similar to memcpy. We change to the REP STOSB operation, which will copy AL into EDI until ECX reaches 0.
_memset: push edi mov edi, [esp + 0x8] mov eax, [esp + 0xc] ; char in al mov ecx, [esp + 0x10] push edi ; store dest cld rep stosb ; ends at ecx = 0 pop eax ; return dest pop edi ret
Here is the C prototype for strcmp:
int strcmp(const char *str1, const char *str2);
The strcmp function returns 0 if both strings are equal, > 0 if the first character that does not match has a greater value in str1 than in str2, and < 0 in the other case.
For this function we need to change our strategy. The REP CMPSB instruction looks like it would be great, but we would need to precompute both strings lengths and then use the minimum for our ECX value. We can achieve a better implementation using more generic looping and comparison constructs. Even though it seems to be more code, by skipping two strlen calls it ends up being less.
_strcmp: push edi push esi mov esi, [esp + 0xc] mov edi, [esp + 0x10] xor eax, eax ; clear ret cmp_loop: mov al, [esi] mov cl, [edi] sub al, cl ; al = *esi - *edi jne cmp_leave test cl, cl ; check for '\0' jz cmp_leave inc esi ; ++esi, ++edi inc edi jmp cmp_loop cmp_leave: pop esi pop edi ret
Here is the C prototype for strset:
char *strset(char *str, int ch);
This is a function that isn't part of the standard library. We assume it works similar to memset, except that it will stop at the null terminator. There are two strategies we could take: precompute the strlen and then do a memset, or use more generic looping and comparison for a tighter implementation.
_strset: push edi mov edi, [esp + 0x8] mov ecx, [esp + 0xc] ; char in ecx push edi ; store dest set_loop: mov al, [edi] test al, al ; check '\0' jz set_leave mov [edi], cl ; *edi = ch inc edi jmp set_loop set_leave: pop eax ; return dest pop edi ret
No comments :
Post a Comment