如何计算 i386 中字符串中 char 的出现次数?
How do I count the occurence of a char in a string in i386?
我是 80386 汇编语言的新手。目前正在努力完成一项要求用汇编语言编写将在 c 程序中调用的函数的学校作业。
extern int count(char *string, char c);
我想我知道应该怎么做,但仍在努力选择正确的指令(指令以 'b'、'w' 或 'l' 结尾),也许“正确的”寄存器,我知道有一些是为特定目的保留的。
.text
.global count
count:
pushl %ebp # set up stack frame
movl %esp,%ebp # save %esp in %ebp
subl , %esp # automatic variables
movl [=10=], %eax # initialize %eax to 0
movl 8(%ebp), %esi # pointer to s
movb 12(%ebp), %bh # pointer to c
check:
movb (%esi), %bl # move the first char in s to %bl
cmp 0, %bl # if the char is [=10=]
je done # job is done
cmp %bh, %bl # else compare the char to %bh
je found1 # if match increase the counter
incb %bl # else move to next char
jmp check
found1:
addl , %eax # found a match
incb %bl
jmp check # go back to the beginning of check
done:
movl %ebp, %esp # restore %esp from %ebp
popl %ebp # restore %ebp
ret
.end
我对这个程序的理解是它应该将两个值(string和char)的地址存储到两个寄存器中。然后通过char访问字符串char,并将其与存储在另一个寄存器中的char进行比较。如果找到匹配项,则增加 %eax 中的 return 值,否则转到字符串中的下一个字符,直到到达结尾 [=12=]
。
我的程序似乎陷入了循环,因为它既没有崩溃也没有输出结果。
我们将不胜感激。
我不会用汇编程序编程所以我让 gcc 帮我编译它:
int count(const char *str, const char ch)
{
int count = 0;
while(*str)
{
if(*str == ch) count++;
str++;
}
return count;
}
count:
pushl %ebx
movl 8(%esp), %edx
movb 12(%esp), %cl
movb (%edx), %al
xorl %ebx, %ebx
testb %al, %al
je .L1
.L4:
cmpb %cl, %al
jne .L3
incl %ebx
.L3:
incl %edx
movb (%edx), %al
testb %al, %al
jne .L4
.L1:
movl %ebx, %eax
popl %ebx
ret
我认为没有真正的理由将 %esp
保存到 %ebp
,或从 %esp
中减去。您确实需要保存 %esi
。我认为a,b,c,d寄存器可以安全丢失,但如果不能(我已经有一段时间没用汇编了),你需要保存%ebx
还有。
(更新:正如@NateEldredge 指出的那样,必须保留 %ebx
- 我忘记更新堆栈指针。是的,已经太久了)。
count:
pushl %esi # save %esi as we use it
pushl %ebx
# "In assembly language, all the labels and numeric constants used
# as immediate operands (i.e. not in an address calculation like
# 3(%eax,%ebx,8)) are always prefixed by a dollar sign."
# https://flint.cs.yale.edu/cs421/papers/x86-asm/asm.html
movl 12(%esp), %esi # pointer to s
movb 16(%esp), %bh # char
# I think it's more common "xor %eax, %eax"
movl [=10=], %eax # initialize %eax to 0
check:
movb (%esi), %bl # move the current char in s to %bl
cmp [=10=], %bl # if the char is [=10=]
je done # job is done
cmp %bh, %bl # else compare the char to %bh
je found1 # if match increase the counter
# We must increase the pointer to the character, not %bl
incl %esi # else move to next char
jmp check
found1:
addl , %eax # found a match
# incb %bl
incl %esi # move to next char
jmp check # go back to the beginning of check
done:
popl %ebx
popl %esi # restore %esi
ret
.end
您也可以反转测试以保存一些指令:
cmp %bh, %bl # else compare the char to %bh
jne notfound # if not match, skip incrementing
addl , %eax # found a match
notfound:
incl %esi # move to next char
jmp check
我是 80386 汇编语言的新手。目前正在努力完成一项要求用汇编语言编写将在 c 程序中调用的函数的学校作业。
extern int count(char *string, char c);
我想我知道应该怎么做,但仍在努力选择正确的指令(指令以 'b'、'w' 或 'l' 结尾),也许“正确的”寄存器,我知道有一些是为特定目的保留的。
.text
.global count
count:
pushl %ebp # set up stack frame
movl %esp,%ebp # save %esp in %ebp
subl , %esp # automatic variables
movl [=10=], %eax # initialize %eax to 0
movl 8(%ebp), %esi # pointer to s
movb 12(%ebp), %bh # pointer to c
check:
movb (%esi), %bl # move the first char in s to %bl
cmp 0, %bl # if the char is [=10=]
je done # job is done
cmp %bh, %bl # else compare the char to %bh
je found1 # if match increase the counter
incb %bl # else move to next char
jmp check
found1:
addl , %eax # found a match
incb %bl
jmp check # go back to the beginning of check
done:
movl %ebp, %esp # restore %esp from %ebp
popl %ebp # restore %ebp
ret
.end
我对这个程序的理解是它应该将两个值(string和char)的地址存储到两个寄存器中。然后通过char访问字符串char,并将其与存储在另一个寄存器中的char进行比较。如果找到匹配项,则增加 %eax 中的 return 值,否则转到字符串中的下一个字符,直到到达结尾 [=12=]
。
我的程序似乎陷入了循环,因为它既没有崩溃也没有输出结果。
我们将不胜感激。
我不会用汇编程序编程所以我让 gcc 帮我编译它:
int count(const char *str, const char ch)
{
int count = 0;
while(*str)
{
if(*str == ch) count++;
str++;
}
return count;
}
count:
pushl %ebx
movl 8(%esp), %edx
movb 12(%esp), %cl
movb (%edx), %al
xorl %ebx, %ebx
testb %al, %al
je .L1
.L4:
cmpb %cl, %al
jne .L3
incl %ebx
.L3:
incl %edx
movb (%edx), %al
testb %al, %al
jne .L4
.L1:
movl %ebx, %eax
popl %ebx
ret
我认为没有真正的理由将 %esp
保存到 %ebp
,或从 %esp
中减去。您确实需要保存 %esi
。我认为a,b,c,d寄存器可以安全丢失,但如果不能(我已经有一段时间没用汇编了),你需要保存%ebx
还有。
(更新:正如@NateEldredge 指出的那样,必须保留 %ebx
- 我忘记更新堆栈指针。是的,已经太久了)。
count:
pushl %esi # save %esi as we use it
pushl %ebx
# "In assembly language, all the labels and numeric constants used
# as immediate operands (i.e. not in an address calculation like
# 3(%eax,%ebx,8)) are always prefixed by a dollar sign."
# https://flint.cs.yale.edu/cs421/papers/x86-asm/asm.html
movl 12(%esp), %esi # pointer to s
movb 16(%esp), %bh # char
# I think it's more common "xor %eax, %eax"
movl [=10=], %eax # initialize %eax to 0
check:
movb (%esi), %bl # move the current char in s to %bl
cmp [=10=], %bl # if the char is [=10=]
je done # job is done
cmp %bh, %bl # else compare the char to %bh
je found1 # if match increase the counter
# We must increase the pointer to the character, not %bl
incl %esi # else move to next char
jmp check
found1:
addl , %eax # found a match
# incb %bl
incl %esi # move to next char
jmp check # go back to the beginning of check
done:
popl %ebx
popl %esi # restore %esi
ret
.end
您也可以反转测试以保存一些指令:
cmp %bh, %bl # else compare the char to %bh
jne notfound # if not match, skip incrementing
addl , %eax # found a match
notfound:
incl %esi # move to next char
jmp check