gpt4 book ai didi

linux - x86-64 Linux 汇编。由于 EFAULT,在 argv 上使用 write 不起作用? "Bad address"

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:19:38 25 4
gpt4 key购买 nike

我最近决定试一试 x86-64 汇编。我在显示 argv 时遇到了问题

是的,我写的代码很糟糕,它会做出假设并且不会检查错误,我知道,但我真的不认为这是这个问题的原因。

这是我的程序的核心。

        .globl  _start
.text
main:
_start:
movl $10,%edx # No. of chars to write
movq 16(%rsp),%rcx # argv[1]
movl $1,%ebx # stdout
movl $4,%eax # write
int $0x80

movl $0,%ebx
movl $1,%eax
int $0x80

我运行我的程序 ./myprog helloworlddddddddd

所以 argv[0] =./myprog和 argv[1] = helloworlddddddddddd 或我输入的任何内容

我的程序应该将 argv[1] 中的前十个字符写入标准输出。

除非它不起作用。写入返回 -14,这是错误 EFAULT?这意味着地址错误。

所以我改写了这个

        .globl  _start
.text
main:
_start:
movq 16(%rsp),%rax
movq $bob,%rbx
subq %rcx,%rcx
.Lloop:
movb (%rax,%rcx),%dl
movb %dl,(%rbx,%rcx)
cmpb $0,%dl
je .Ldone
addq $1,%rcx
jmp .Lloop

.Ldone: movl $10,%edx
movq $bob,%rcx
movl $1,%ebx
movl $4,%eax
int $0x80

movl $0,%ebx
movl $1,%eax
int $0x80

.comm bob,50

它将 argv[1] 复制到我称为 bob 的内存区域,然后尝试将此副本写入标准输出。我确定它是糟糕的 x86,但它可以工作。如果我编译并运行该程序,它会输出 argv[1]

中的内容

最后我用C写了这个

#include <unistd.h>

int main(int argc, char **argv) {
write(1,argv[1],10);

return 0;
}

这比我的第二个程序更像我的第一个程序,但也有效。到了这个阶段,我完全感到困惑。

所以在我看来,“写入”系统调用不允许读取我程序的 argv 数组,但它可以读取副本。哦,如果我只是用 C 编写它,它就可以工作。这看起来很奇怪。谁能告诉我这是怎么回事,为什么?


编辑:

有人指出我混合使用了 32 位和 64 位代码。所以我改为 100% 64 位。

第一个程序:

    .globl  _start
.text
main:
_start:
movl $10,%edx # No. of chars to write
movl 16(%rsp),%esi # argv[1]
movl $1,%edi # stdout
movl $1,%eax # write
syscall

movl $0,%edi
movl $60,%eax
syscall

第二个程序:

    .globl  _start
.text
main:
_start:
movq 16(%rsp),%rax
movq $bob,%rbx
subq %rcx,%rcx
.Lloop:
movb (%rax,%rcx),%dl
movb %dl,(%rbx,%rcx)
cmpb $0,%dl
je .Ldone
addq $1,%rcx
jmp .Lloop

.Ldone: movl $10,%edx # No. of chars to write
movq $bob,%rsi # buffer
movl $1,%edi # stdout
movl $1,%eax # write
syscall

movl $0,%edi # return 0
movl $60,%eax # exit
syscall

.comm bob,50

仍然是同样的错误,第一个程序即使现在是 64 位仍然无法运行,第二个程序仍然可以运行,即使它现在也是 64 位

第一个程序的 64 位版本的 Strace。 (不起作用的那个):

execve("./Myprog", ["./Myprog", "bananablahblah"], [/* 46 vars */]) = 0
write(1, 0x1491f543, 10) = -1 EFAULT (Bad address)
_exit(0) = ?
+++ exited with 0 +++

最佳答案

你在这里犯了三个主要错误:

  1. 您混淆了 main_start。它们不是同义词——_start 的标准 C 库实现在调用 main 之前做了一些重要的初始化。您可能不想尝试重新实现 _start — 不要在您的可执行文件中定义它;链接到 libc 以获取它。

  2. 您正在尝试在 64 位可执行文件中使用 32 位系统调用 (int $0x80)。这不能正常工作;特别是,它无法读取 4GB 边界以上的内存,包括您的堆栈!您必须使用 syscall 指令进行 64 位系统调用。但是请记住,它使用略有不同的调用约定,并使用不同的调用号码!

  3. 您在某些需要 64 位等效项的位置使用 32 位指令和寄存器。这有时适用于低指针和值,但会截断一些其他值。养成在 64 位代码中始终使用 64 位指令和寄存器的习惯,除非您特别需要更小的东西(例如,char 的 8 位寄存器)。

关于linux - x86-64 Linux 汇编。由于 EFAULT,在 argv 上使用 write 不起作用? "Bad address",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24216759/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com