【问题标题】:Exit program x86退出程序 x86
【发布时间】:2015-12-01 15:09:56
【问题描述】:

我正在学习 x86 汇编。我试图了解“退出程序”如何在 x86 上工作。我们有一个代码:

push ebp
mov ebp,esp
//Some stuff here
mov esp, ebp
pop ebp
ret

当处理器执行“ret”指令时:

EIP 将有值,从堆栈中弹出,即 0。 因此处理器将转到 0 地址并尝试执行不包含程序代码/可执行代码的指令。 那么,处理器到底发生了什么?是否有条件检查,例如if EIP = 0 -> exit program?Or if ESP out of bounds -> exit program?`处理器如何理解这条RET指令是程序的结束?

【问题讨论】:

  • “程序”和“退出”的概念仅在操作系统的上下文中才有意义。请查阅您的操作系统手册,了解如何以编程方式访问这些概念。 (在典型的桌面操作系统上,会有用于创建和退出进程的系统调用。)
  • ".. 从堆栈中弹出,即 0。"你是怎么得出这个结论的?你的程序是不是叫做“从地址 0”?

标签: assembly x86 stack exit


【解决方案1】:

main() 从正常的 C 运行时初始化函数中调用。用任何语言(包括 asm)编写 main 与编写任何其他函数没有什么不同。

_start 开始执行。如果你自己写_start,它就没有什么可返回的了,所以你需要进行_exit(2)exit_group(2)系统调用。

(否则,当执行超出代码末尾时会出现段错误,或者如果您尝试ret,它将从堆栈中弹出一个值到程序计数器(EIP)中,并且可能会在代码获取时出现段错误可能是无效的地址。)

当您使用 C 编译器编译 + 链接时,它会链接 CRT(C 运行时)启动代码,该代码提供一个 _start,它初始化 libc 然后调用 mainmain 返回后,调用它的 CRT 代码运行 atexit 函数,然后将 main 的返回值传递给退出系统调用。

_start 不是函数,它是进程入口点。例如,在 Linux 下,在进入 _start 时,ESP 指向 argc,而不是返回地址。 (请参阅 i386 System V ABI。)


这个问题是从不同的角度提出的,但my answer 对另一个最近的问题更详细。

与往常一样,使用调试器单步执行是查看正在发生的事情并测试您的理解的好方法。

【讨论】:

    【解决方案2】:

    进程被操作系统终止。如果您看到返回指令,则在您的函数之前有一个(“隐藏”)函数,然后返回执行。

    在 Linux(32 位)环境中终止进程的一种方法是调用特定的系统调用:sys_exit

    mov     eax, 0 // interrupt code
    mov     ebx, 0 // argument, in this case: return value
    int     0x80
    

    这可能是你的函数之前的函数。以上代码将命令返回给操作系统,然后操作系统退出您的进程。

    【讨论】:

    • eax=0 / int 0x80sys_restart_syscall您希望 mov eax, 1 用于 32 位 int 0x80 ABI 中的 sys_exit,或 x86-64 syscall ABI 中的 eax=60。 (或eax=231 / syscall 用于sys_exit_group,退出所有线程,like libc's exit(3) uses 在刷新 stdio 缓冲区和其他清理之后。)当然,xor ebx,ebx 是推荐将寄存器归零的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    相关资源
    最近更新 更多