Image may be NSFW.
Clik here to view.Earlier today I wrote some assembly code to compare 2 strings and print out whether or not they were equal to one another. I’ve been learning more assembly and so I thought I would tweak it a bit to improve the way it works and add more “features”. After some studying I’ve managed to get it working as a real function that actually takes arguments via the stack. On top of that, the function now returns a value that designates the index where the comparison failed; this is stored in the EAX register. Even further, by using a buffer in memory I was able to print a string that informs the user of the index where the comparison failed.
String Comparison Part 2
The strings being compared are stored in Str1 and Str2 directly in the .data section of the code. They are passed in as parameters by utilizing the stack. This took much longer than my first attempt, which always used the same strings and did not utilize the stack.
The code
This will print out “Strings are equal!” when executed. If you modify Str1 or Str2 so that they are not equal, you will see “Strings are not equal!” instead; depending on the modifications you make you may have to adjust the EBX register in _start since it contains the string length.
This particular example has a limitation that it will only work as designed for strings up to 10 characters. This is because when printing the index where the strings differ I have to convert the decimal value to ascii. The simple method I’m using to do this is to add the number 48, which only works on numbers between 0 and 9.
I’ll also point out that I use the 64-bit registers frequently in this code because I’m on a 64-bit machine and I have to push the 64-bit memory addresses onto the stack. Therefore this one will look quite a bit different from the last one.
.data Str1: .asciz "abcdefghi" Str2: .asciz "abcdefghi" StrEqual: .asciz "Strings are equal!\n" StrNotEqual: .asciz "Strings are not equal!\n" StrDiffer: .asciz "Strings differ at index !\n" .bss .lcomm StrDifferBuff 100 .text .globl _start .type StrCmp, @function .type PrintEqual, @function .type PrintNotEqual, @function _start: # for stepping through the debugger nop # string length is stored in rbx movq $10, %rbx # push the arguments to StrCmp onto the stack (in the reverse order that I'll pop them off) pushq %rbx pushq $Str2 pushq $Str1 # compare the strings call StrCmp # restore the stack pointer addq $24, %rsp # if EAX is the string length, the strings are equal cmp %ebx, %eax # if the comparison was successful the strings are equal jz CallPrintEqual # else they were not equal # push the arguments to PrintNotEqual onto the stack pushq %rax # print the difference call PrintNotEqual # restore the stack pointer addq $8, %rsp jmp Finish CallPrintEqual: call PrintEqual # finish up (both branches of the above if-else flow will get here) Finish: jmp ExitProgram ###################################### # compare two strings of equal length # @param str1 # @param str2 # @param strlength # @ret the index at which the two strings differ or $strLength if the strings are equal ###################################### StrCmp: # save the current base pointer by pushing it onto the stack pushq %rbp # move the base pointer to the top of the stack movq %rsp, %rbp # retrieve our arguments from the stack movq 16(%rbp), %rsi movq 24(%rbp), %rdi movq 32(%rbp), %rcx # save the string length into EAX movl %ecx, %eax # clear the direction flag if it's set cld # continue comparing each character in the strings until they do not match # or the end of the string is reached ContinueCmp: cmpsb loopz ContinueCmp # place the index of the character that did not match into EAX sub %ecx, %eax # restore the base pointer and return popq %rbp ret ExitProgram: movl $1, %eax movl $0, %ebx int $0x80 ###################################### # print that the strings are not equal and the index where the comparison failed # @param index ###################################### PrintNotEqual: # save the current base pointer by pushing it onto the stack pushq %rbp # move the base pointer to the top of the stack movq %rsp, %rbp # retrieve our arguments from the stack movq 16(%rbp), %rax # put the string into the buffer movl $StrDiffer, %esi movl $StrDifferBuff, %edi movl $28, %ecx rep movsb # increment eax by 48 to get the ascii representation of the integer addl $48, %eax # overwrite the last space in the string with the index where # the strings differ movb %al, StrDifferBuff+24 # write StrNotEqual movl $4, %eax movl $1, %ebx leal StrNotEqual, %ecx movl $24, %edx int $0x80 # write StrDifferBuff movl $4, %eax movl $1, %ebx leal StrDifferBuff, %ecx movl $28, %edx int $0x80 # restore the base pointer and return popq %rbp ret ###################################### # print that the strings are equal ###################################### PrintEqual: movl $4, %eax movl $1, %ebx leal StrEqual, %ecx movl $20, %edx int $0x80 ret