系统调用只读/写1字节



我是程序集的新手,正在尝试编写一个版本的"回声;内置,但一次只能操作1个字节。

我有以下内容,它按照我想要的方式工作,只是它在读取和写入时都溢出了超过1个字节,尽管我在两个系统调用中都明确表示x2中有1个字节。我做错了什么?

示例运行:

sh-4.2$ ./echo1b
f
f
o
o
b
b
bar
bar
bazbazbaz
bazbazbaz
q
sh-4.2$

这是代码:

.data
temp:   .byte 1  
.text
.globl _start
_start:
/* read one byte from stdin, store to temp */
mov x0, #0x0
adr x1, temp
mov x2, #0x1
mov x8, #0x3F
svc #0x0
/* write newline to stdout */
mov x0, #0x1
mov x1, #0xA
mov x2, #0x1
mov x8, #0x40
svc #0x0

/* if byte in temp is "q", exit */
mov x5, #0x71
ldr x1, temp
cmp x1, x5
beq exit
/* otherwise, write it to stdout and repeat */
mov x0, #0x1
adr x1, temp
mov x2, #0x1
mov x8, #0x40
svc #0x0
b _start
exit:
/* exit cleanly */  
eor x0, x0, x0 
eor x1, x1, x1
eor x2, x2, x2
mov x8, #0x5D
svc #0x0

您的代码中存在以下几个问题:

  • 如注释中所述,当调用sys_write时,输出缓冲区的地址必须在x1中,就像调用temp一样
  • 当比较temp和换行符时,必须使用ldrb w1, [x0]而不是ldr x1, temp,其中x0指向temp。后者将读取4个字节,而不能保证上面的三个字节为零

我还改进了您代码的某些部分:

  • cmp可以与12位立即数一起使用,因此不需要将0x71放入寄存器
  • 将第二个CCD_ 11调用移动到CCD_
  • sys_exit仅使用x0作为参数,因此不需要将x1x2设置为零

这是在Raspbian 4.19上测试的最终代码(基于debian(:

.data
temp:    .byte 1
newline: .byte 0x0A
.text
.globl _start
loop:
// 4: Otherwise, write it to stdout and repeat
mov  x0, #0x1    // int    fd
adr  x1, temp    // void*  buf
mov  x2, #0x1    // size_t count
mov  x8, #0x40   // sys_write
svc  #0x0

_start:
// 1: Read one byte from stdin and store to temp (including newline)
mov  x0, #0x0   // int    fd
adr  x1, temp   // void*  buf
mov  x2, #0x1   // size_t count
mov  x8, #0x3F  // sys_read
svc  #0x0

// 2: If byte in temp is 'q', exit
adr  x0, temp
ldrb w1, [x0] // instead of temp
cmp  x1, #0x71
bne  loop
// 5: Exit cleanly
eor  x0, x0, x0  // int status
mov  x8, #0x5D   // sys_exit
svc  #0x0

注释后编辑:要在退出时刷新stdin,可以在步骤5:之前添加以下行

// 5: Flush stdin (read until newline)
flush:
mov  x0, #0x0   // int    fd
adr  x1, temp   // void*  buf
mov  x2, #0x1   // size_t count
mov  x8, #0x3F  // sys_read
svc  #0x0
adr  x0, temp
ldrb w1, [x0]
cmp  x1, #0x0A
bne flush       // loop until x0 == 0x0A