所以我正在编写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]但最后添加了额外的字符,我无法弄清楚原因。 有什么想法??
答案 0 :(得分:1)
在
mov %ecx, %edi /*Add null terminating char to new str*/
指令不会向内存写入任何内容;它只是将一个零复制到寄存器%edi
本身。如果我没记错的话,内存写入的正确语法类似于
movb %cl, (%edi)
但是在复制过程中精心存储零终结符在%cl
中毫无意义,因为你知道它无论如何都会变为零。所以只是
movb $0, (%edi)
应该也一样。
(另外,但是无关,字符串指令实际上比单独的加载/存储和递增/递减操作的等效组合慢。至少这是围绕486或早期奔腾时代的情况,它会让我感到惊讶如果它仍然不正确 - 特别是如果你需要每次都操纵方向标志。)
((另外,对于你不使用的所有内容,声明输出变量似乎是毫无意义的。有什么意义。即使你需要对eax
的使用进行硬编码字符串指令,简单地列出clobber列表中的"eax"
比将其强制为虚拟输出变量要清楚得多。)