【发布时间】:2021-03-03 04:28:43
【问题描述】:
我有一个用 c 和汇编编写的小程序。原理很简单:“计算 main.c 给出的字符串中的‘0’
所以对于test0 str0ing 0,它应该返回3,因为字符串中有3个'0'
函数本身是用 AT&T 语法在 x86 asm 中创建的,我通过 C 获得了一个指向字符串的指针。main.c 和 asm 都通过头文件链接。
到目前为止,这是我的代码,问题是它总是返回 0。它永远不会达到条件跳转以递增 %eax(要返回)
// C
#include "asm.h"
char string[] = "2a0 a0 ";
char *ptr1 = string;
int main(){
printf("\nthere are : %d %s in :%s", zero_count(), "0s", string);
printf("\nstring address is: %p\n", ptr1);
return 0;
}
// x86asm
.global ptr1
.section .text
.global zero_count #func()
zero_count:
# prologue
pushl %ebp # save these previous stack frame pointer
movl %esp, %ebp # the stack frame pointer for function
# save registers
#pushl $ebx # needs to be pushed out of stack when used
#pushl %esi # needs to be pushed out of stack when used
#pushl %edi # needs to be pushed out of stack when used
# function body
movl ptr1, %ecx # moves the value of ptr1 to ecx
movl $0, %eax # cleans eax with 0
# loop start
loop_beginning:
cmp $0, (%ecx)
je end
# compare to 'o'
cmp $48, %ecx # 48 is "0" in the asci table
je if_0
increment_pointer:
addl $1, %ecx
jmp loop_beginning
if_0:
addl $1, %eax
jmp increment_pointer
end:
#popl %edi # needs to be popped when used
#popl %esi # needs to be popped when useds
#popl %ebx # needs to be popped when used
# epilogue
movl %ebp, %esp # restore the previous stack pointer("cleaner" the stack)
popl %ebp # restore the previous stack frame pointer
ret #w returns
我为提前使用全局变量道歉,我知道这不好但我仍在学习使用堆栈
【问题讨论】:
-
cmp $48, %ecx- ECX 持有一个指针,而不是一个字符值。由于您要检查0(终止符)和'0'(ASCII 数字),您应该将movzbl加载到像EDX 这样的寄存器中。 -
还要注意
cmp $48, (%ecx)是一个双字,而不是一个字节比较。请改用cmpb $48, (%ecx)。 -
@fuz:知道 GAS 是否会像
mov $0, (%ecx)那样接受cmp $0, (%ecx)上的错误补丁作为不明确的操作数大小吗?这似乎并不罕见。顺便说一句,我查看了现有的重复项,但没有运气。不过,我确信有多个问答是比较指针而不是指向的数据,因此只发表评论。 -
@PeterCordes 不确定。也许对
.att_syntax指令有一个新选项? IIRC LLVM 汇编器实际上可能拒绝模棱两可的操作数大小。 -
@fuz 但不是 ecx 将填充 16 位地址吗?我只是比较与()指向的地址是什么