linux程序集反转一个字符串

时间:2011-09-14 22:35:29

标签: linux assembly x86

所以我正在编写c中的内联汇编函数,它反转字符串的内容并将反转的字符串放在一个新的字符数组中,但是我在反向字符串的末尾添加了额外的字符。

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;
}

装配功能

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;
    }

在这种情况下你好,世界!得到打印[!dlroW,olleH]但最后添加了额外的字符,我无法弄清楚原因。 有什么想法??

1 个答案:

答案 0 :(得分:1)

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

指令不会向内存写入任何内容;它只是将一个零复制到寄存器%edi本身。如果我没记错的话,内存写入的正确语法类似于

movb %cl, (%edi)

但是在复制过程中精心存储零终结符在%cl中毫无意义,因为你知道它无论如何都会变为零。所以只是

movb $0, (%edi)

应该也一样。

(另外,但是无关,字符串指令实际上比单独的加载/存储和递增/递减操作的等效组合慢。至少这是围绕486或早期奔腾时代的情况,它会让我感到惊讶如果它仍然不正确 - 特别是如果你需要每次都操纵方向标志。)

((另外,对于你不使用的所有内容,声明输出变量似乎是毫无意义的。有什么意义。即使你需要对eax的使用进行硬编码字符串指令,简单地列出clobber列表中的"eax"比将其强制为虚拟输出变量要清楚得多。)