Quantcast
Viewing all articles
Browse latest Browse all 6

Comparing Strings in Assembly Part 2

Image may be NSFW.
Clik here to view.
Edit
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

Viewing all articles
Browse latest Browse all 6

Trending Articles