在汇编中获取字符串的第一个字符
Getting first character of string in assembly
我正在尝试编写一个比较单个字符的程序,但它说缓冲区不等于 'S' 即使我给了一个作为输入,我知道有一个换行符和终止符在输入字符串之后但 [.buffer] 不只是应该给出字符串的第一个字符吗?
section .text
global main
main:
jmp start_promt
start_promt:
section .data
.promt db "Choose one of the following instructions: (S)tart, (Q)uit",10,0
.promtLen equ $-.promt-1 ; memory address of begin of this instruction minus memory address of begin of promt gives length of promt
.bufsize dq 100
section .bss
.buffer resd 100
section .text
mov rax, 1 ; rax <- 0 (syscall number for 'write')
mov rdi, 1 ; rdi <- 0 (stdout file descriptor)
mov rsi, .promt ; address of prompt message
mov rdx, .promtLen ; size of promt message
syscall ; execute write(1, promt, promtLen)
xor rax, rax ; rax <- 0 (syscall number for 'read')
xor rdi, rdi ; rdi <- 0 (stdin file descriptor)
mov rsi, .buffer ; rsi <- address of the buffer. lea rsi, [rel buffer]
mov rdx, [.bufsize] ; rdx <- size of the buffer
syscall ; execute read(0, buffer, BUFSIZE)
mov rdx, [.buffer]
cmp rdx, 'S'
je start_game
cmp rdx, 'Q'
je quit
jmp start_promt
start_game:
; loop for user-instructions
; if done
;jmp start_promt
quit:
mov rax, 60
mov rdi, 0
syscall
继续上面的评论,比较失败是因为您试图将单个字节 'S'
或 'Q'
与 8 字节寄存器进行比较。那行不通的。 rdx
还有 7 个字节不会是 'S'
或 'Q'
并且每次测试都会失败。
步进gdb
中的每条指令使其易于查看。 运行 gdb yourexecutable
,然后 break _start
在程序开始时创建断点。 (为方便起见,通过设置 display/i $pc
显示当前正在执行的命令)现在只需使用 si
来逐步执行您的代码。当您进入数据输入和比较时,检查 .buffer
和 rdx
的内容,例如
1: x/i $pc
=> 0x4000e5 <start_promt+51>: syscall
(gdb)
SoooRO
0x00000000004000e7 in start_promt ()
1: x/i $pc
=> 0x4000e7 <start_promt+53>: mov 0x600150,%rdx
(gdb) x/6c 0x600150
0x600150: 83 'S' 111 'o' 111 'o' 111 'o' 82 'R' 79 'O'
(gdb) si
0x00000000004000ef in start_promt ()
1: x/i $pc
=> 0x4000ef <start_promt+61>: cmp [=10=]x53,%rdx
(gdb) info reg rdx
rdx 0xa4f526f6f6f53 2901965242593107
在上面你可以看到在提示符下输入了 "SoooRO"
只是为了填充一些额外的字符。 .buffer
的地址是 0x600150
所以你可以用 x/6c 0x600150
检查缓冲区的内容(检查缓冲区中的 6 个字符)你会看到:
0x600150: 83 'S' 111 'o' 111 'o' 111 'o' 82 'R' 79 'O'
一切都很好 -- 那么为什么比较失败了?这也显示在调试中:
=> 0x4000ef <start_promt+61>: cmp [=12=]x53,%rdx
(gdb) info reg rdx
rdx 0xa4f526f6f6f53 2901965242593107
你看到寄存器的位置 0xa4f526f6f6f53
(最后一个字节是 ASCII 0x53
- 'S'
)。
那么如何解决这个问题呢?使用正确的寄存器来存储一个字节。 dl
是一字节寄存器,dx
是两字节寄存器,edx
是四字节寄存器,rdx
是八字节寄存器。因此将第一个字符移动到 dl
然后与 dl
进行比较将进行您正在寻找的单字符比较,例如
mov dl, [.buffer]
cmp dl, 'S'
je start_game
cmp dl, 'Q'
je quit
如果您还有其他问题,请告诉我。
我正在尝试编写一个比较单个字符的程序,但它说缓冲区不等于 'S' 即使我给了一个作为输入,我知道有一个换行符和终止符在输入字符串之后但 [.buffer] 不只是应该给出字符串的第一个字符吗?
section .text
global main
main:
jmp start_promt
start_promt:
section .data
.promt db "Choose one of the following instructions: (S)tart, (Q)uit",10,0
.promtLen equ $-.promt-1 ; memory address of begin of this instruction minus memory address of begin of promt gives length of promt
.bufsize dq 100
section .bss
.buffer resd 100
section .text
mov rax, 1 ; rax <- 0 (syscall number for 'write')
mov rdi, 1 ; rdi <- 0 (stdout file descriptor)
mov rsi, .promt ; address of prompt message
mov rdx, .promtLen ; size of promt message
syscall ; execute write(1, promt, promtLen)
xor rax, rax ; rax <- 0 (syscall number for 'read')
xor rdi, rdi ; rdi <- 0 (stdin file descriptor)
mov rsi, .buffer ; rsi <- address of the buffer. lea rsi, [rel buffer]
mov rdx, [.bufsize] ; rdx <- size of the buffer
syscall ; execute read(0, buffer, BUFSIZE)
mov rdx, [.buffer]
cmp rdx, 'S'
je start_game
cmp rdx, 'Q'
je quit
jmp start_promt
start_game:
; loop for user-instructions
; if done
;jmp start_promt
quit:
mov rax, 60
mov rdi, 0
syscall
继续上面的评论,比较失败是因为您试图将单个字节 'S'
或 'Q'
与 8 字节寄存器进行比较。那行不通的。 rdx
还有 7 个字节不会是 'S'
或 'Q'
并且每次测试都会失败。
步进gdb
中的每条指令使其易于查看。 运行 gdb yourexecutable
,然后 break _start
在程序开始时创建断点。 (为方便起见,通过设置 display/i $pc
显示当前正在执行的命令)现在只需使用 si
来逐步执行您的代码。当您进入数据输入和比较时,检查 .buffer
和 rdx
的内容,例如
1: x/i $pc
=> 0x4000e5 <start_promt+51>: syscall
(gdb)
SoooRO
0x00000000004000e7 in start_promt ()
1: x/i $pc
=> 0x4000e7 <start_promt+53>: mov 0x600150,%rdx
(gdb) x/6c 0x600150
0x600150: 83 'S' 111 'o' 111 'o' 111 'o' 82 'R' 79 'O'
(gdb) si
0x00000000004000ef in start_promt ()
1: x/i $pc
=> 0x4000ef <start_promt+61>: cmp [=10=]x53,%rdx
(gdb) info reg rdx
rdx 0xa4f526f6f6f53 2901965242593107
在上面你可以看到在提示符下输入了 "SoooRO"
只是为了填充一些额外的字符。 .buffer
的地址是 0x600150
所以你可以用 x/6c 0x600150
检查缓冲区的内容(检查缓冲区中的 6 个字符)你会看到:
0x600150: 83 'S' 111 'o' 111 'o' 111 'o' 82 'R' 79 'O'
一切都很好 -- 那么为什么比较失败了?这也显示在调试中:
=> 0x4000ef <start_promt+61>: cmp [=12=]x53,%rdx
(gdb) info reg rdx
rdx 0xa4f526f6f6f53 2901965242593107
你看到寄存器的位置 0xa4f526f6f6f53
(最后一个字节是 ASCII 0x53
- 'S'
)。
那么如何解决这个问题呢?使用正确的寄存器来存储一个字节。 dl
是一字节寄存器,dx
是两字节寄存器,edx
是四字节寄存器,rdx
是八字节寄存器。因此将第一个字符移动到 dl
然后与 dl
进行比较将进行您正在寻找的单字符比较,例如
mov dl, [.buffer]
cmp dl, 'S'
je start_game
cmp dl, 'Q'
je quit
如果您还有其他问题,请告诉我。