繁体   English   中英

如何使用 Linux 上的 mmap 系统调用解决我在此 x86-64 汇编代码中遇到的 EINVAL 和 EPERM 错误

[英]How do I troubleshoot the EINVAL and EPERM errors I'm getting in this x86-64 assembly code using the mmap syscall on Linux

我在弄清楚我在这段代码中做错了什么时遇到了一些麻烦,我将不胜感激任何可用的帮助:

.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 的 output ---

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

感谢您帮助我找到解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM