nasm汇编中的调用函数时出现分段错误

Shubham Kumar

我试图在nasm中调用我自己的函数,它可以工作2次,然后给出细分错误。我创建了两个函数display1和display2,分别显示“ This is message1”和“ This is message2”。这些功能第一次正确,但是在两次调用这些功能时显示分段错误。

global _start

section .text

display1:
    mov eax, 0x4
    mov ebx, 0x1
    mov ecx, var1
    mov edx, len1
    int 0x80
    ret
display2:
    mov eax, 0x4
    mov ebx, 0x1
    mov ecx, var2
    mov edx, var2
    int 0x80
    ret

_start:
    call display1
    call display2
    call display1
    call display2
    mov eax, 0x1
    mov ebx, 0x5
    int 0x80

section .data

    var1: db "This is message1", 0x0A, 0x00
    len1 equ $-var1
    var2: db "This is message2", 0x0A, 0x00
    len2 equ $-var2

This is message1
This is message2
.symtab.strtab.shstrtab.text.data�N!�$�'
    �U�����"'��,1��6�=���I���P���functions.nasmdisplay1display2var1len1var2len2_start__bss_start_edata_endThis is message1
This is message2
.symtab.strtab.shstrtab.text.data�N!�$�'
    �U�����"'��,1��6�=���I���P���functions.nasmdisplay1display2var1len1var2len2_start__bss_start_edata_endSegmentation fault (core dumped)
彼得·科德斯

恭喜,您已经找到了一个内核错误(在您非常老的Ubuntu 12.04 / Linux 3.13.0-32-通用32位内核中)。

mov edx, var2传递一个非常大的整数(地址)作为size这就是为什么在第二条消息之后会出现垃圾的原因。write系统调用读取内存高达附近某处未映射的页面,然后停止。

在非Buggy内核上,然后write返回并继续执行,直到_exit您期望系统调用为止

该指令int 0x80导致分段错误。

IDK是否比破坏用户空间或稍后导致故障更疯狂。

可能不值得在任何地方报告此内核错误。Ubuntu 12.04 LTS于2017年停产该错误在现代内核中不存在,并且可能是由于该内核为最新版本以来7年内其他更改的一部分而被偶然发现或修复。


最终会从未映射的页面读取的具有write()的非嵌入式内核中发生了什么

write(2)手册页绝对不会记录坏ARGS提高只是像错误代码的信号,的可能性EFAULT

我无法在带有x86-64 Linux内核5.0.1的Arch Linux上重现该段错误;我得到了预期的垃圾写入,然后write(2)返回写入未映射页面之前写入的字节数。然后继续执行直到_exit(5)系统调用,并且进程以status = 5干净退出。

我以为在传递包含未映射页面的指针+大小时,即使写了一些字节后write也可能会返回-EFAULT,但事实并非如此。手册页中的措词没有提及这种特定情况,但是有关如何处理在编写过程中发现的其他错误的措辞与此一致。(通常,这些错误是由于磁盘已满或管道另一端关闭引起的。)

write(2) Linux手册页

请注意,成功的write()传输的字节数可能少于计数字节。发生这种部分写入的原因可能多种多样。...
...
在一个部分写入的情况下,主叫方可以使另一个write()调用传输剩余的字节。随后的调用将传输更多的字节,或者可能导致错误(例如,如果磁盘现在已满)。

Linux的肯定并不会总是一路,当你做到这一点传输到最后一个页面映射结束。但是有趣的是看到不同情况下会发生什么。

似乎它是按块复制的,并随着每个块检查其可读性。当从未映射的页面读取块时,将检测到错误,并返回部分写入。如果再打一次电话address = buf + first_retval,您可能会得到一个-EFAULT因此,这非常像用部分写操作填充磁盘,然后-ENOSPC在尝试写其余部分时通过获取进行检测

将输出重定向到tmpfsx86-64 Linux 5.0.1上的文件(中),我得到write()4078.的大小4096-18 = 4078,并且我使用的是最新的ld(Binutils 2.32),因此该.data部分在可执行文件中以4k对齐,并且以该部分在内存中也是页面对齐的。因此,页面的结尾位于var2 + 4096 - len1

$ strace ./2write > foo
strace: [ Process PID=28961 runs in 32 bit mode. ]
write(1, "This is message1\n\0", 18)    = 18
write(1, "This is message2\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 134520850) = 4078
write(1, "This is message1\n\0", 18)    = 18
write(1, "This is message2\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 134520850) = 4078
exit(5)                                 = ?
+++ exited with 5 +++

与写入终端相比,我的大小为 2048

与写入相比/dev/null,写入返回成功134520850null特殊块设备的驱动程序甚至不读取用户空间内存,它只是从write使它走那么远的系统调用中返回成功因此,没有什么可以检查的-EFAULT

将输出传递给wc,在第一个坏调用和-EFAULT一个坏调用中,我得到了令人惊讶的18字节部分写入

strace ./2write | wc
execve("./2write", ["./2write"], 0x7ffdba771cf0 /* 53 vars */) = 0
strace: [ Process PID=29008 runs in 32 bit mode. ]
write(1, "This is message1\n\0", 18)    = 18
write(1, "This is message2\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 134520850) = 18
write(1, "This is message1\n\0", 18)    = 18
write(1, "This is message2\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 134520850) = -1 EFAULT (Bad address)
exit(5)                                 = ?
+++ exited with 5 +++
      3       9      54

在程序的后续运行中,我-EFAULT马上就知道了我猜想Linux在第一次调用后可能已经为管道缓冲区分配了更多的内存,因此在复制任何数据之前,它能够向前看足够远,立即注意到错误的地址。

peter@volta:/tmp$ strace ./2write | wc
execve("./2write", ["./2write"], 0x7fff868a41b0 /* 53 vars */) = 0
strace: [ Process PID=29015 runs in 32 bit mode. ]
write(1, "This is message1\n\0", 18)    = 18
write(1, "This is message2\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 134520850) = -1 EFAULT (Bad address)
write(1, "This is message1\n\0", 18)    = 18
write(1, "This is message2\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 134520850) = -1 EFAULT (Bad address)
exit(5)                                 = ?
      2       6      36

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

从C程序调用x86汇编函数时出现分段错误

取消引用调用函数中的指针时出现分段错误

调用 strcpy 函数时出现分段错误

调用MPF函数时出现分段错误

从Eigen调用Lapack函数时出现分段错误

从Python调用cpp函数时出现分段错误

在ruby上调用c函数时出现分段错误

在C ++ 11中调用Lambda从高阶函数返回时出现分段错误

C ++中调用fortran子例程时出现分段错误

X86汇编:在主函数中执行“ ret”后出现分段错误,为什么?

读取指向函数中的变量时出现分段错误

尝试克隆函数时出现分段错误(在C中)

在函数中声明char数组时出现分段错误

在我的 strpbrk 函数中返回 nullptr 时出现分段错误

调用free()时出现分段错误

调用printf%s时出现分段错误

从指针调用方法时出现分段错误

使用clock()函数时出现分段错误

函数返回时出现分段错误

运行 PAM 函数时出现分段错误

调用用 C 编写的 Postgres 函数时出现分段错误,使 Postgres 服务器崩溃

使用Python C API两次调用C函数时出现分段错误

第二次调用函数时出现分段错误?

乘寄存器时汇编中的分段错误?

使cat -b函数时出现分段错误错误

LWJGL 代码中第一次调用 gl* 时出现分段错误

调用vfprintf函数后出现分段错误(核心已转储)

调用gtk_main_quit会导致汇编代码中出现“分段错误”

在ADF中调用Azure函数时出现错误“ BadRequest”