mike
mike

Reputation: 3519

linux assembly reverse a string

SO I am working on writing an inline assembly function in c that reverses that contents of a string and puts the reversed string in a new character array, but I am getting extra characters added to the end of my reversed string.

int main(int argc, char **argv) {
    char *new_str;
    char old_str[20] = "Hello, World!";
    mystrrev(new_str, old_str, strlen(old_str));
    printf("New string: %s\n", &new_str);
    return 0;
}

Assembly function

char *mystrrev(char *dest, const char *src, int size) {
        int d0, d1, d2, d3;
      __asm__ (
                    "add %%ebx, %%esi\n\t"          /*Move to end of string*/
                    "std\n\t"                       /*Decrement esi after load*/
                    "lodsb\n\t"                     /*Load esi into al*/
                    "sub $1, %%ebx\n\t"
                    "mov %%al, %%cl\n\t"            /*mov contents of al to cl*/
                    "1:\tstd\n\t"                   /*Begin loop, decrement esi after load*/
                    "lodsb\n\t"                     /*Load esi into al*/
                    "cld\n\t"                       /*Clear flg*/
                    "stosb\n\t"                     /*Store al in edi*/
                    "sub $1, %%ebx\n\t"             /*subtract 1 from strlenght counter*/
                    "cmp $0, %%ebx\n\t"             /*Compare ebx to 0*/
                    "jne 1b\n\t"
                    "mov %%ecx, %%edi\n\t"          /*Add null terminating char to new str*/
                    : "=&S"(d0), "=&D"(d1), "=&a"(d2), "=&b" (d3)   /*output*/
                    /*** &S --> ESI,  &D --> EDI,  &a --> eax ***/
                    : "0" (src), "1" (dest), "3" (size)     /*input*/
                    : "memory");                            /*clobber registers*/
      return dest;
    }

In this case Hello, World! gets printed out [!dlroW, olleH] but there are extra characters added at the end and I cannot figure out why. Any thoughts??

Upvotes: 1

Views: 817

Answers (1)

hmakholm left over Monica
hmakholm left over Monica

Reputation: 23332

The

mov %ecx, %edi       /*Add null terminating char to new str*/

instruction does not write anything to memory; it just copies a zero into the register %edi itself. The correct syntax for a memory write, if I remember correctly, is something like

movb %cl, (%edi)

But it is really pointless to meticulously store the zero terminator in %cl during the copying, because you know it's going to be a zero anyway. So just

movb $0, (%edi)

ought to work just as well.

(Also, but unrelated, the string instructions are actually slower than equivalent combinations of separate load/store and increment/decrement operations. At least this used to be the case around the 486 or early Pentium era, and it would surprise me if it's not still true -- especially if you need to manipulate the direction flag each time anyway).

((Also also, it appears to be rather pointless to declare output variables for everything that you don't use anyway. What's the point of that. Even if you need to hardcode the use of eax for the string instructions, simply listing "eax" in the clobber list is immensely clearer than forcing it into a dummy output variable)).

Upvotes: 1

Related Questions