反转字符串并在 IA32 程序集中打印它
Reversing a string and printing it in IA32 assembly
所以基本上我是在尝试读取一个字符串,增加一个计数器(在本例中为 %edx)直到我读取一个 \n,然后倒退打印它。
这是我的代码:
.section .data
cadsal:
.asciz "Por favor ingrese su cadena:\n"
leer:
.asciz "%s"
salidafinal:
.asciz "La cadena introducida, invertida es:\n"
imp:
.asciz "%c\n"
.section .bss
.comm cadena,50,1
.section.text
.globl _start
_start:
leal cadsal, %eax
pushl %eax
call printf
addl , %esp
leal cadena, %eax
pushl %eax
leal leer, %eax
pushl %eax
call scanf
addl , %esp
xorl %edx, %edx
对比:
movb cadena(%edx), %al
incl %edx
cmpb [=12=], %al
jne Contar
leal salidafinal, %ecx
pushl %ecx
call printf
addl , %esp
addl $-2, %edx
反转:
movb cadena(%edx), %al
pushl %eax
leal imp, %ebx
pushl %ebx
call printf
addl , %esp
decl %edx
cmpl [=13=], %edx
jge Invertir
movl , %eax
int [=13=]x80
我在编译时使用命令-nostartfiles。它有效,但是当我 运行 它时,输入 "Invertir" 时出现分段错误。我需要帮助来检测此代码中的错误。
谢谢!
您的直接问题是 cmpb '\n', %al
,它缺少 at&t 语法中要求的 $
符号以使其成为立即数。实际上,'\n'
被认为是一个地址,并且是一个无效地址。你应该使用 cmpb $'\n', %al
.
但是 scanf
根本不会将 '\n'
放入您的缓冲区,因为 %s
在空格处停止。所以你真的想寻找一个终止零字节,那就是使用 cmpb [=17=], %al
。或者,如果您确实需要阅读整行,请改用 fgets
。
如果你解决了这个问题,你将 运行 进入下一个问题,即你的 cmp
和 jne
之间有一个 incl %edx
,这将改变标志,这样您就不会在比较结果上分支,而是在增量上分支。解决方案:交换 cmp
和 incl
.
还有一个问题是一些寄存器,包括 %edx
,是调用者保存的。因此,它们可以被调用的函数修改,而你可以 call printf
。您应该 push
/pop
围绕这两个以保留值。
即使在所有这些之后,由于缓冲,您可能在手动打印最终 \n
之前看不到任何输出。
请注意,如果你打算使用 C 库,你真的不应该使用 -nostartfiles
。相反,您应该正常使用入口点 main
和 assemble 以及 link。此外,您应该简单地从 main
(或最多 call exit
)中选择 return,而不是使用直接系统调用,因为这不允许 C 库正确清理。顺便说一句,这也会刷新 I/O 缓冲区,因此即使没有额外的换行符,您也会看到输出。
你真的应该学会使用调试器。
所以基本上我是在尝试读取一个字符串,增加一个计数器(在本例中为 %edx)直到我读取一个 \n,然后倒退打印它。
这是我的代码:
.section .data
cadsal:
.asciz "Por favor ingrese su cadena:\n"
leer:
.asciz "%s"
salidafinal:
.asciz "La cadena introducida, invertida es:\n"
imp:
.asciz "%c\n"
.section .bss .comm cadena,50,1
.section.text
.globl _start
_start:
leal cadsal, %eax
pushl %eax
call printf
addl , %esp
leal cadena, %eax
pushl %eax
leal leer, %eax
pushl %eax
call scanf
addl , %esp
xorl %edx, %edx
对比:
movb cadena(%edx), %al
incl %edx
cmpb [=12=], %al
jne Contar
leal salidafinal, %ecx
pushl %ecx
call printf
addl , %esp
addl $-2, %edx
反转:
movb cadena(%edx), %al
pushl %eax
leal imp, %ebx
pushl %ebx
call printf
addl , %esp
decl %edx
cmpl [=13=], %edx
jge Invertir
movl , %eax
int [=13=]x80
我在编译时使用命令-nostartfiles。它有效,但是当我 运行 它时,输入 "Invertir" 时出现分段错误。我需要帮助来检测此代码中的错误。
谢谢!
您的直接问题是 cmpb '\n', %al
,它缺少 at&t 语法中要求的 $
符号以使其成为立即数。实际上,'\n'
被认为是一个地址,并且是一个无效地址。你应该使用 cmpb $'\n', %al
.
但是 scanf
根本不会将 '\n'
放入您的缓冲区,因为 %s
在空格处停止。所以你真的想寻找一个终止零字节,那就是使用 cmpb [=17=], %al
。或者,如果您确实需要阅读整行,请改用 fgets
。
如果你解决了这个问题,你将 运行 进入下一个问题,即你的 cmp
和 jne
之间有一个 incl %edx
,这将改变标志,这样您就不会在比较结果上分支,而是在增量上分支。解决方案:交换 cmp
和 incl
.
还有一个问题是一些寄存器,包括 %edx
,是调用者保存的。因此,它们可以被调用的函数修改,而你可以 call printf
。您应该 push
/pop
围绕这两个以保留值。
即使在所有这些之后,由于缓冲,您可能在手动打印最终 \n
之前看不到任何输出。
请注意,如果你打算使用 C 库,你真的不应该使用 -nostartfiles
。相反,您应该正常使用入口点 main
和 assemble 以及 link。此外,您应该简单地从 main
(或最多 call exit
)中选择 return,而不是使用直接系统调用,因为这不允许 C 库正确清理。顺便说一句,这也会刷新 I/O 缓冲区,因此即使没有额外的换行符,您也会看到输出。
你真的应该学会使用调试器。