为什么当我在程序集.bss部分保留较少的内存时,直到我保留0时才出现段错误?

问题描述 投票:0回答:1

我正在编写一个程序,它只是获取我的 CPU 名称并要求我的操作系统将其打印出来。 我使用cpuid操作,效果很好。但一开始我必须为字符串保留一些内存,48 个字节用于我从 eax:ebx:ecx:edx 获得的 3 部分信息,还有一个用于存储 符号:

section .bss
cpuname resb 49

所以,我的代码对于初学者来说效果非常好:

section .text
        global _start

_start:
        xor edi, edi ; using edi for memory address shift because every step I use 16 bytes (4 bytes*4 registers)
regcpy:        
        mov eax, 0x80000002 ; specific number for cpuid command to get my CPU name
        mov esi, edi
        shr esi, 4          ; I want to do it three times
        add eax, esi        ; up to 0x80000004 as it was described for cpuid
        cpuid
        mov [cpuname + edi], eax
        mov [cpuname + 4 + edi], ebx
        mov [cpuname + 8 + edi], ecx
        mov [cpuname + 12 + edi], edx
        add edi, 16
        cmp edi, 48         ; three iterations overall: 16, 32, 48 and when 48
        jne regcpy          ; I don't repeat it and proceed the program downwards

        mov [cpuname + 48], byte 10 ; adding \n because otherwise it's ugly

        mov rax, 1
        mov rdi, 1
        mov rsi, cpuname
        mov rdx, 49         ; asking the OS to print ASCII symbols with addresses
        syscall             ; from 'cpuname' byte up to 'cpuname+48' byte out

        mov rax, 60
        xor rbx, rbx
        syscall             ; 60 = 0x3c it's sys_exit for x86_64

如果我尝试在 .bss 部分保留更少的内存,就会发生我不明白的事情:

section .bss
cpuname resb 40

section .bss
cpuname resb 2

编译并工作正常,我得到输出:我的 CPU 的全名,而看起来应该存在分段错误。 但是当我预订0时,

section .bss
cpuname resb 0

它成功地出现了段错误。 我有一个模糊的假设,当我使用 resb [number >= 0] 时,我的操作系统至少保留了一些特定数量的字节,因此它不会出现段错误,除非我的写入尝试的“长度”达到一些具体的数字。 就像即使我写 resb 1,Linux 也会保留 64、128 或...我不知道,我只是想猜测。或者我完全错了,不是吗?但是……当我尝试在 C 中做类似的事情时,即使 1 字节溢出也会导致段错误? 请告诉我为什么当我想要的时候却无法让我的程序出现段错误

assembly memory segmentation-fault heap-memory
1个回答
0
投票

虚拟内存在 pages 上运行,在 x86 上为 4 Kib。当您访问尚未映射到进程地址空间的页面时,就会发生段错误。

因此,如果访问“无效”地址与任何有效内存不在同一页面上,只会导致段错误。您的程序可能以这样的方式链接,即

.bss
部分是页面对齐的,以便它从新页面开始,并且其大小是整数页。因此,如果大小非零,则至少会分配一页,并且 4096 字节以内的访问不会出错。如果大小为零,则可能会分配 0 个页面,因此 .bss 部分的开头位于未映射的页面上,并且所有访问都会出错。然而,这种行为并不能得到保证;在某些情况下
.bss
可能会与其他程序数据共享一个页面,那么大小和出错地址之间的关系就会不同。

请注意,无论是否发生段错误,访问未专门为此目的分配的内存位置仍然是“错误”。如果您写入这样的地址,您可能会无意中覆盖程序中的一些其他数据。如果你读了它,即使它没有错误,如果你不知道它的含义或是谁把它放在那里,你读到的值也是没有用的。

© www.soinside.com 2019 - 2024. All rights reserved.