x86汇编 - 根据ASCII码打印字符

3

我是一名新手汇编程序员,遇到了在屏幕上打印字符的问题。每次执行程序时,都会出现分段错误,我不知道原因在哪里。

.section .data
  A:
    .long  65  # ascii code for 'A'

.section .text
.globl _start

_start:
 movl $1, %edx # length of character to print, 1
 movl  A, %ecx # what I want printed
 movl $1, %ebx # file descriptor for STDOUT
 movl $4, %eax # syscall number for sys_write

 int $0x80     # calls kernel

 movl $0, %ebx # return status
 movl $1, %eax # syscall number for sys_exit

 int $0x80     # calls kernel

这些是我用来构建的命令(我的文件名为write.s)

as write.s -o write.o
ld write.o -o write

这不是打印字符的正确方法吗?任何帮助将不胜感激。


你是如何组装/链接它的?请注意,它需要是一个32位可执行文件。 - Paul R
我正在使用linux的标准汇编器和链接器。我将添加上述命令,因为它们很重要。file 命令将我的可执行文件列为32位ELF文件。 - Hunter McMillen
1
你是否使用过调试器来检查参数是否设置正确? - Niklas B.
由于A是一个地址,因此我本以为movl会加载该地址。但是leal完成了这项工作。您介意将其作为答案,并指点我可以用于汇编的调试器吗?@NiklasB。 - Hunter McMillen
你读过 http://tldp.org/HOWTO/Assembly-HOWTO/ 吗?你有用 strace 跟踪你的程序吗? - Basile Starynkevitch
@BasileStarynkevitch,不是的,我一直在跟随一本叫做“从组装语言开始编程”的书,但我一定会看看那个。谢谢。 - Hunter McMillen
1个回答

2
movl A, %ecx

意思是:将标签A的地址处的值复制到%ecx中。正确的指令应该是:
movl $A, %ecx

或者

leal A, %ecx

在这些情况下,您可以使用GDB进行调试(请注意,您必须使用-g标志进行汇编以获取调试信息):

$ as -g write.s -o write.o
$ ld write.o -o write
$ gdb write
GNU gdb (GDB) 7.5
   [.. snip ..]
(gdb) b test.s:13
Breakpoint 1 at 0x4000c6: file test.s, line 13.
(gdb) run
Starting program: /home/niklas/tmp/asm/write 

Breakpoint 1, _start () at test.s:13
13   int $0x80     # calls kernel
(gdb) info registers ecx
ecx            0x41 65

如您所见,%ecx 具有整数值 65,这不是您想要的。


如果您运行 strace ./write,它将为您解码系统调用参数并返回值。当您传递错误指针时,您会看到 write() 只返回 -EFAULT 而不做任何其他操作。


你知道我怎么打印一个不在数据区域的值吗?比如说,如果我只想打印字母'A',它的ASCII码是65。有没有办法加载立即值? - Hunter McMillen
@Hunter:你可以将它放在堆栈上:pushl $0x41 # movl %esp, %ecx。请注意,您还需要确保字符串以空字符结尾(由于小端序,这里是这种情况)。当然,您也可以使用 subl [size], %esp 来预留空间。 - Niklas B.
我最终也找到了如何在GDB中设置断点的方法 :) - Niklas B.
不是所有的“字符串”都需要以空字符结尾 - 这不是C语言! - Frank Kotler
@Frank:非常正确,我太习惯用汇编对抗libc了 :/ - Niklas B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接