我的code at github出了什么问题?
read
正常但第二个突然显示EBADF
。fd
硬编码为3使其成功读取并以多个块打印文件。fd
绑定传递,如github上的master分支所示,这样它也可以工作。fd
位置的内存内容在发出第一个read
系统调用后立即被损坏。让我觉得fd
后面的内存在读入buf
时会被覆盖,但我不明白为什么。
main.asm中:
%define SYS_READ 0
%define SYS_WRITE 1
%define SYS_OPEN 2
%define SYS_MMAP 9
%define SYS_EXIT 60
%define PROT_READ 0x1
%define PROT_WRITE 0x2
%define MAP_ANONYMOUS 0x20
%define MAP_PRIVATE 0x02
%define STD_OUT 1
%define STD_ERR 2
%define O_RDONLY 0
%define CHUNK_SIZE 0x10 ; small to get multiple chunk reads on
; small input
; %define CHUNK_SIZE 0x1000 ; 4KiB
section .data
buf dq 0
fd dq 0
merr_read_failed db "read() failed", 0xa
merr_read_failed_size equ $-merr_read_failed
merr_open_failed db "open() failed", 0xa
merr_open_failed_size equ $-merr_read_failed
section .text
global _start
_start:
; unused labels make it easier to set breakpoints in gdb
open_file:
pop rdi
pop rdi
; pop argv[1] into rdi
pop rdi
; exit if NULL
cmp rdi, 0
je exit_bad
; open argv[1]
mov rax, SYS_OPEN
mov rsi, O_RDONLY
syscall
cmp rax, 0
jl err_open_failed
mov [fd], rax
jmp read_chunk
allocate_buffer:
mov rax, SYS_MMAP
mov rdi, 0x0
mov rsi, CHUNK_SIZE
mov rdx, PROT_READ | PROT_WRITE
mov r10, MAP_ANONYMOUS | MAP_PRIVATE
mov r8, -1
mov r9, 0
syscall
mov [buf], rax
read_chunk:
mov rax, SYS_READ
mov rdi, [fd]
mov rsi, buf
mov rdx, CHUNK_SIZE
syscall
; check for error
cmp rax, 0
jl err_read_failed
; save read byte count to r10
mov r10, rax
print_chunk:
; if last read yielded 0 bytes, exit.
; as 0 signifies an EOF
cmp r10, 0
je exit_ok
mov rax, SYS_WRITE
mov rdi, STD_OUT
mov rsi, buf
mov rdx, r10
syscall
; repeat
jmp read_chunk
err_open_failed:
mov rax, SYS_WRITE
mov rdi, STD_ERR
mov rsi, merr_open_failed
mov rdx, merr_open_failed_size
syscall
jmp exit_bad
err_read_failed:
mov rax, SYS_WRITE
mov rdi, STD_ERR
mov rsi, merr_read_failed
mov rdx, merr_read_failed_size
syscall
jmp exit_bad
exit_bad:
mov rdi, 1
jmp exit
exit_ok:
mov rdi, 0
jmp exit
exit:
mov rax, SYS_EXIT
syscall
生成文件:
all:
nasm -g -f elf64 -o main.o main.asm
ld -o main main.o
strace的:
% strace ./main Makefile
execve("./main", ["./main", "Makefile"], [/* 54 vars */]) = 0
open("Makefile", O_RDONLY) = 3
read(3, "all:\n\n\tnasm -g -", 16) = 16
write(1, "all:\n\n\tnasm -g -", 16all:
nasm -g -) = 16
read(544043873, 0x6001e8, 16) = -1 EBADF (Bad file descriptor)
write(2, "read() failed\n", 14read() failed
) = 14
_exit(1) = ?
+++ exited with 1 +++
GDB:
(gdb) disassemble
Dump of assembler code for function read_chunk:
=> 0x000000000040014c <+0>: mov $0x0,%eax
0x0000000000400151 <+5>: mov 0x6001ec,%rdi
0x0000000000400159 <+13>: movabs $0x6001e4,%rsi
0x0000000000400163 <+23>: mov $0x10,%edx
0x0000000000400168 <+28>: syscall
0x000000000040016a <+30>: cmp $0x0,%rax
0x000000000040016e <+34>: jl 0x4001b1 <err_read_failed>
0x0000000000400170 <+36>: mov %rax,%r10
End of assembler dump.
(gdb) p 0x6001ec
$1 = 6291948
(gdb) i r rdi
rdi 0x0 0
(gdb) si
0x0000000000400151 in read_chunk ()
(gdb) i r rdi
rdi 0x0 0
(gdb) p 0x6001ec
$2 = 6291948
(gdb) x 0x6001ec
0x6001ec <fd>: 0x00000003
(gdb) si
0x0000000000400159 in read_chunk ()
(gdb) x 0x6001ec
0x6001ec <fd>: 0x00000003
(gdb) si
0x0000000000400163 in read_chunk ()
(gdb) x 0x6001ec
0x6001ec <fd>: 0x00000003
(gdb) si
0x0000000000400168 in read_chunk ()
(gdb) x 0x6001ec
0x6001ec <fd>: 0x00000003
(gdb) si
0x000000000040016a in read_chunk ()
(gdb) x 0x6001ec
0x6001ec <fd>: 0x206d7361
(gdb) disassemble
Dump of assembler code for function read_chunk:
0x000000000040014c <+0>: mov $0x0,%eax
0x0000000000400151 <+5>: mov 0x6001ec,%rdi
0x0000000000400159 <+13>: movabs $0x6001e4,%rsi
0x0000000000400163 <+23>: mov $0x10,%edx
0x0000000000400168 <+28>: syscall
=> 0x000000000040016a <+30>: cmp $0x0,%rax
0x000000000040016e <+34>: jl 0x4001b1 <err_read_failed>
0x0000000000400170 <+36>: mov %rax,%r10
End of assembler dump.
(gdb)
答案 0 :(得分:1)
您永远不会调用allocate_buffer
指令,并且在read_chunk
和print_chunk
中使用了错误的间接级别。应用此修补程序后,您的代码将起作用:
diff --git a/main.asm b/main.asm
index c9c98e4..8c44223 100644
--- a/main.asm
+++ b/main.asm
@@ -51,7 +51,6 @@ open_file:
cmp rax, 0
jl err_open_failed
mov [fd], rax
- jmp read_chunk
allocate_buffer:
mov rax, SYS_MMAP
@@ -67,7 +66,7 @@ allocate_buffer:
read_chunk:
mov rax, SYS_READ
mov rdi, [fd]
- mov rsi, buf
+ mov rsi, [buf]
mov rdx, CHUNK_SIZE
syscall
@@ -85,7 +84,7 @@ print_chunk:
mov rax, SYS_WRITE
mov rdi, STD_OUT
- mov rsi, buf
+ mov rsi, [buf]
mov rdx, r10
syscall
jmp
删除允许执行allocate_buffer
指令,另外两个更改使系统调用使用已分配内存的地址而不是存储此地址的地址。
发生了什么事?
您没有为strace显示缓冲区分配内存(不执行mmap系统调用)。 buf
是数据部分中8字节内存(dq
)的地址,在程序启动时初始化为0。
您的代码会直接读入buf
,从而覆盖数据部分的内容,包括fp
之后的buf
。 read_chunk
的第二次迭代在fp
中找到一个奇怪的值并崩溃。
当您跳过分配并更改代码以读入[buf]
时,正如我们在评论中所讨论的那样,您会读到地址0,从现在出现明显的原因,它甚至更早地破坏了您的程序。