I have got an assembly function strcmp
, which I use with C. This is the function-
; strcmp-
; takes rdi and rsi as the string
; this function always returns 0 if strings were equal, else 1, stored in rax
BITS 64
section .text
global strcmp
strcmp:
push r15
push r14
mov r15, 0
jmp strcmp_loop
strcmp_loop:
mov r14, [rdi+r15]
cmp r14, [rsi+r15] ; compare s1[i] and s2[i]
jne exit_fail
cmp r14, 0 ; compare s1[i] with NULL. No need to do the same with s2[i] since s1[i] and s2[i] will be equal at this point
je exit_success
inc r15
jmp strcmp_loop
exit_success:
mov rax, 0
jmp exit
exit_fail:
mov rax, 1
jmp exit
exit:
pop r14
pop r15
ret
And io_funcs.c-
#include "io_funcs.h"
int main() {
char s[] = "Hello World!\n", test[14];
puts(s);
strcpy(test, s);
puts(test);
if(!strcmp(s, test)) {
puts("Equal!!!! :-)");
} else {
puts("Unequal!!! :-(");
}
putc('\n');
return 0;
}
which I compile with gcc o/* c/io_funcs.c -static -nostdlib
(I assemble my assembly programs in directory o/
using nasm
). When I run it, I get-
$ ./a.out
Hello World!
Hello World!
Unequal!!! :-(
When I try debugging it a bit, I get-
$ gdb ./a.out -q
Reading symbols from ./a.out...
(gdb) b strcmp
Breakpoint 1 at 0x401120: file asm/strcmp.asm, line 10.
(gdb) run
Starting program: /home/spot/coding/asm/io_funcs/a.out
Hello World!
Hello World!
Breakpoint 1, strcmp () at asm/strcmp.asm:10
10 push r15
(gdb) p (char *)$rdi
$1 = 0x7fffffffe16a "\210\341\377\377\377\177"
(gdb) p (char *)$rsi
$2 = 0x7fffffffe15c "Hello World!\n"
(gdb) p (char *)$rdx
$3 = 0x7fffffffe15c "Hello World!\n"
(gdb)
This seems to mean that rsi and rdx contain the arguments, and rdi maybe just garbage (or something else?).
When I replace this line
if(!strcmp(s, test)) {
with this
if(!strcmp("Hello World!\n", test)) {
the program seems to give me this-
$ gdb ./a.out -q
Reading symbols from ./a.out...
(gdb) b strcmp
Breakpoint 1 at 0x401120: file asm/strcmp.asm, line 10.
(gdb) run
Starting program: /home/spot/coding/asm/io_funcs/a.out
Hello World!
Hello World!
Breakpoint 1, strcmp () at asm/strcmp.asm:10
10 push r15
(gdb) p (char *)$rdi
$1 = 0x402000 "Hello World!\n"
(gdb) p (char *)$rsi
$2 = 0x7fffffffe15c "Hello World!\n"
(gdb)
but also gives the output Unequal!!! :-(
.
But when I replace the similar line with
if(!strcmp("Hello World!\n", "Hello World!\n")) {
the program seems to give me correct output-
$ ./a.out
Hello World!
Hello World!
Equal!!!! :-)
Why does this happen? And how can I solve it?
Also note that all the functions that I am using, have been implemented by me, by my own in assembly (just for a practice of assembly). And they all seem to work except for the strcmp
function.
Edit-
After following the advice of checking my strings after strcpy
execution in the comments, I see that string s
has been changed.
$ gdb ./a.out -q
Reading symbols from ./a.out...
(gdb) b 8
Breakpoint 1 at 0x40105f: file c/io_funcs.c, line 8.
(gdb) run
Starting program: /home/spot/coding/asm/io_funcs/a.out
Hello World!
Breakpoint 1, main () at c/io_funcs.c:8
8 puts(test);
(gdb) p (char *)test
$1 = 0x7fffffffe15c "Hello World!\n"
(gdb) p (char *)s
$2 = 0x7fffffffe16a "\210\341\377\377\377\177"
(gdb)
(Note that strcpy
executes at line 7, so I am checking this right after the function call.)
So, I might have done a mistake in my strcpy
function. Please check for any errors that you might see in it-
strcpy.asm-
; strcpy-
; takes rdi and rsi as the string
; this function always returns 0, stored in rax
BITS 64
section .text
global strcpy
strcpy:
push r15
push r14
mov r15, 0
jmp strcpy_loop
strcpy_loop:
mov r14, [rsi+r15]
mov [rdi+r15], r14
cmp [rsi+r15], byte 0
je exit
inc r15
jmp strcpy_loop
exit:
mov rax, 0
pop r14
pop r15
ret