我尝试制作一个汇编代码来计算字符串中有多少个字符,但是我收到错误。
代码,我使用gcc和intel_syntax
#include <stdio.h>
int main(){
char *s = "aqr b qabxx xryc pqr";
int x;
asm volatile (
".intel_syntax noprefix;"
"mov eax, %1;"
"xor ebx,ebx;"
"loop:"
"mov al,[eax];"
"or al, al;"
"jz print;"
"inc ebx;"
"jmp loop"
"print:"
"mov %0, ebx;"
".att_syntax prefix;"
: "=r" (x)
: "r" (s)
: "eax", "ebx"
);
printf("Length of string: %d\n", x);
return 0;
}
我得到了错误:
Error: invalid use of register
最后我想创建程序,搜索正则表达式模式([pq] [^ a] + a)并打印它的起始位置和长度。我用C编写它,但我必须使它在汇编中工作: 我的C代码:
#include <stdio.h>
#include <string.h>
int main(){
char *s = "aqr b qabxx xryc pqr";
int y,i;
int x=-1,length=0, pos = 0;
int len = strlen(s);
for(i=0; i<len;i++){
if((s[i] == 'p' || s[i] == 'q') && length<=0){
pos = i;
length++;
continue;
} else if((s[i] != 'a')) && pos>0){
length++;
} else if((s[i] == 'a') && pos>0){
length++;
if(y < length) {
y=length;
length = 0;
x = pos;
pos = 0;
}
else
length = 0;
pos = 0;
}
}
printf("position: %d, length: %d", x, y);
return 0;
}
答案 0 :(得分:1)
您在jmp loop
和print:
之后省略了分号。
你的asm也无法正常工作。将指针移动到s
到eax,然后用mov al,[eax]
覆盖它。所以下一次通过循环,eax不再指向字符串了。
当你解决这个问题时,你需要考虑这样一个事实,即每次通过循环都需要改变eax指向下一个字符,否则mov al,[eax]
会继续读取相同的字符。
由于您还没有接受答案(点击左侧的复选标记),还有一段时间可以再进行一次编辑。
通常我不会做人的作业,但是已经过了几天。据推测,作业的截止日期已经过去。在这种情况下,这里有一些解决方案,既可用于OP的教育,也可用于未来的SO用户:
1)遵循任务的(有些奇怪的)限制:
asm volatile (
".intel_syntax noprefix;"
"mov eax, %1;"
"xor ebx,ebx;"
"cmp byte ptr[eax], 0;"
"jz print;"
"loop:"
"inc ebx;"
"inc eax;"
"cmp byte ptr[eax], 0;"
"jnz loop;"
"print:"
"mov %0, ebx;"
".att_syntax prefix;"
: "=r" (x)
: "r" (s)
: "eax", "ebx"
);
2)违反一些分配规则以制作更好的代码:
asm (
"\n.intel_syntax noprefix\n\t"
"mov eax, %1\n\t"
"xor %0,%0\n\t"
"cmp byte ptr[eax], 0\n\t"
"jz print\n"
"loop:\n\t"
"inc %0\n\t"
"inc eax\n\t"
"cmp byte ptr[eax], 0\n\t"
"jnz loop\n"
"print:\n"
".att_syntax prefix"
: "=r" (x)
: "r" (s)
: "eax", "cc", "memory"
);
这使用少1个寄存器(无ebx
)并省略(不必要的)volatile
限定符。它还增加了&#34; cc&#34; clobber表示代码修改了标志,并使用&#34; memory&#34; clobber确保任何&#39;待定&#39;在执行asm之前,写入s
的内容会刷新到内存中。它还使用格式化(\ n \ t),因此具有-S
的建筑物的输出是可读的。
3)高级版本使用更少的寄存器(无eax
),检查以确保s
不为NULL(返回-1),使用符号名称并假设-masm=intel
导致更易读的代码:
__asm__ (
"test %[string], %[string]\n\t"
"jz print\n"
"loop:\n\t"
"inc %[length]\n\t"
"cmp byte ptr[%[string] + %[length]], 0\n\t"
"jnz loop\n"
"print:"
: [length] "=r" (x)
: [string] "r" (s), "[length]" (-1)
: "cc", "memory"
);
摆脱(任意且没有深思熟虑)赋值约束允许我们将其减少到7行(如果我们不检查NULL则为5行,如果我们不计算标签则为3行[其中实际上并没有说明])。
有一些方法可以进一步改进(使用标签上的%=
以避免可能的重复符号问题,使用本地标签(.L
),甚至编写它以便它适用于 -masm=intel
和-masm=att
等),但我敢说这3个中的任何一个都比原始问题中的代码更好。
库巴,我不确定在你接受答案之前你还有什么。不过,它确实让我有机会加入彼得的版本。
4)指针递增:
__asm__ (
"cmp byte ptr[%[string]], 0\n\t"
"jz .Lprint%=\n"
".Loop%=:\n\t"
"inc %[length]\n\t"
"cmp byte ptr[%[length]], 0\n\t"
"jnz .Loop%=\n"
".Lprint%=:\n\t"
"sub %[length], %[string]"
: [length] "=&r" (x)
: [string] "r" (s), "[length]" (s)
: "cc", "memory"
);
这不会执行&#39; NULL指针&#39;从#3开始检查,但它确实执行了指针递增&#39;那是彼得推荐的。它还避免了潜在的重复符号(使用%=
),并使用&#39; local&#39;标签(以.L
开头的标签)以避免额外的符号被写入目标文件。
来自&#34;表演&#34;从这个角度来看,这可能会略微好一点(我还没有定时)。然而,从一个&#34;学校项目&#34;从观点来看,#3的清晰度似乎是更好的选择。从一个&#34;我会在现实世界中写什么如果出于某些奇怪的原因我不得不在asm中写这个而不仅仅是使用标准的c函数&#34;从观点来看,我可能会考虑使用情况,除非这对性能至关重要,否则我很想与#3一起使用,以便日后维护。