linux - 如何在 Linux 上使用 mmap 系统调用解决我在此 x86-64 汇编代码中遇到的 EINVAL 和 EPERM 错误
问题描述
我在弄清楚我在这段代码中做错了什么时遇到了一些麻烦,我将不胜感激任何可用的帮助:
.global _start
.section .text
_start:
# Grab our first argument from the stack
popq %rdi # This will be argc, which we don't care about
popq %rdi # Now the executable's path
popq %rdi # And the first argument, at last
# Open the file with open(argv[1], 0, O_RDONLY)
movq $2, %rax # The syscall number for open
xor %rsi, %rsi # There are no flags we need to specify
xor %rdx, %rdx # O_RDONLY is 0
syscall # Do the syscall
# Get the file length with lseek(rax, 0, SEEK_END)
pushq %rax # Save our file descriptor
pushq %rax # For the next lseek
pushq %rax # For mmap
movq $8, %rax # The syscall number for lseek
popq %rdi # Our file descriptor
xor %rsi, %rsi # The offset from where we're seeking in the file
movq $2, %rdx # SEEK_END is 2
syscall # Do the syscall
popq %rbx # Put the file descriptor into rbx so it can be last
pushq %rax # Then save the length
pushq %rbx # Put the file descriptor on the stack
# Now go back to the beginning of the file with
# lseek(fd, 0, SEEK_SET)
movq $8, %rax # lseek again
popq %rdi # Put the file descriptor in rdi
xor %rsi, %rsi # The start of the file
xor %rdx, %rdx # SEEK_SET is 0
syscall # Do the syscall
# Now that we _finally_ have the length of the file,
# mmap(0, length, PROT_READ (1), MAP_SHARED (1), fd, 0)
popq %rdi # The length of the file
popq %rax # Empty the stack
movq $1, %rsi # The permissions we want for the pages containing the file contents
movq $1, %rdx # We want other programs to see our changes (not that there will be any)
pushq $0 # The offset
pushq %rdi # Need this for write
pushq %rdi
xor %rdi, %rdi # We don't give a sh*t about the address
pushq %rax # The file descriptor
movq $9, %rax # mmap's number
syscall # Damn, that took too much setup
# Write out the mmap'ed "buffer" with write(stdout, mmap'ed stuff, the length value we've been yeeting around)
movq %rax, %rdi # mmap'ed stuff
movq $1, %rax # write's syscall number
popq %rsi # The length
syscall # write
# Exit (note: we could unmap the file, but exiting yeets that sh*t out the window for us)
mov $60, %rax # exit is 60
xor %rdi, %rdi # 0
syscall # Exit
基本上,我试图打开作为第一个参数给出的文件名,然后确定文件的长度,将其映射,然后将映射的页面写入标准输出。经过一些调试,似乎我传递了无效的标志、长度或无效的文件描述符。
再次感谢任何帮助,并提前感谢。
--- 编辑:这是 strace 的输出 ---
execve("./mmap_asm_test", ["./mmap_asm_test", "file"], 0x7ffc2cc61038 /* 48 vars */) = 0
brk(NULL) = 0x558c01b67000
arch_prctl(0x3001 /* ARCH_??? */, 0x7fffd5f8eae0) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffa4432c000
arch_prctl(ARCH_SET_FS, 0x7ffa4432ca80) = 0
mprotect(0x558c015ba000, 4096, PROT_READ) = 0
open("file", O_RDONLY) = 3
lseek(3, 0, SEEK_END) = 5
lseek(3, 0, SEEK_SET) = 0
mmap(NULL, 1, PROT_READ, MAP_FILE, 0, 0) = -1 EINVAL (Invalid argument)
write(-22, 0x3, 1) = -1 EBADF (Bad file descriptor)
exit(0) = ?
+++ exited with 0 +++
解决方案
感谢对这个问题的有用评论,我制作了一个按预期工作的程序的修订版本:
.global _start
.section .text
_start:
# Grab our first argument from the stack
popq %rdi # This will be argc, which we don't care about
popq %rdi # Now the executable's path
popq %rdi # And the first argument, at last
# Open the file with open(argv[1], 0, O_RDONLY)
movq $2, %rax # The syscall number for open
xor %rsi, %rsi # There are no flags we need to specify
xor %rdx, %rdx # O_RDONLY is 0
syscall # Do the syscall
movq %rax, %rdi # Put the file descriptor in rdi for later use
# Get the file length with lseek(rax, 0, SEEK_END)
movq $8, %rax # The syscall number for lseek
xor %rsi, %rsi # The offset from where we're seeking in the file
movq $2, %rdx # SEEK_END is 2
syscall # Do the syscall
movq %rax, %r10 # Save our file length
# Now go back to the beginning of the file with
# lseek(fd, 0, SEEK_SET). The file descriptor should still be in rdi here
movq $8, %rax # lseek again
xor %rsi, %rsi # The start of the file
xor %rdx, %rdx # SEEK_SET is 0
syscall # Do the syscall
# Now that we _finally_ have the length of the file,
# mmap(0, length, PROT_READ (1), MAP_SHARED (1), fd, 0)
movq $9, %rax # mmap's number
xor %r9, %r9 # The offset
movq %rdi, %r8 # The file descriptor
movq %r10, %rsi # The file length
movq $1, %rdx # The permissions we want for the pages containing the file contents
movq $1, %r10 # We want other programs to see our changes (not that there will be any)
xor %rdi, %rdi # We don't give a sh*t about the address
syscall # Damn, that took too much setup
# Write out the mmap'ed "buffer" with write(stdout, mmap'ed stuff, length)
movq %rsi, %rdx # The length
movq %rax, %rsi # mmap'ed stuff
movq $1, %rax # write's syscall number
movq $1, %rdi # stdout
syscall # write
# Exit (note: we could unmap the file, but exiting yeets that sh*t right out the window for us)
mov $60, %rax # exit is 60
xor %rdi, %rdi # 0
syscall # Exit
感谢您帮助我找到解决方案。
推荐阅读
- sql - 限制 postgresql jsonb_agg 数组中的对象数量
- sql - 检查字符串是否包含 SQLite 中的任何整数
- sql - 根据while循环的当前迭代获取值
- macos - 如何在 macOS 上设置 GridDB
- jquery - .getJSON 的帮助只能部分工作
- react-native - 反应原生异步等待白屏
- c# - 使用渲染器(世界空间)在游戏对象周围绘制边界矩形(屏幕空间)(Unity)
- php - 我想将活动的获胜日设置为工作日,但是否可以解决错误?
- mysql - 使用带有临时变量的 MySQL CASE 语句,CASE 结果不正确?
- javascript - 如何获取 youtube iframe 的当前时间但不是十进制?