硬编码地址上的 x86 内存访问分段错误,0xFFF

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

出于好奇,我正在学习 x86 汇编。我目前正在使用基于 Linux 的操作系统和 NASM 汇编程序。我很难理解为什么

SECTION .text

global _start

_start:

    nop
    mov ebx, 25
    mov [0xFFF], ebx

   ;Exit the program
   mov eax, 1
   mov ebx, 0
   int 0x80

会导致段错误(当将 ebx 寄存器的内容移动到内存位置 0xFFF 时)。我在想用纯 asm 构建一个程序会让我不受限制地访问我的进程的虚拟地址空间。不是这样吗?

你会如何在汇编中实现像堆这样的东西?

linux assembly x86 segmentation-fault nasm
2个回答
6
投票

在 Linux(x86) 上——尽管您的进程中有一个 4gb 的虚拟地址范围,但并不是所有的都可以访问。上层1gb是内核所在的地方,还有不能使用的低内存区域。虚拟内存地址 0xfff 无法写入或读取(默认情况下),因此您的程序会因段错误而崩溃。

在后续评论中,您建议您打算在汇编程序中创建一个堆。这是可以做到的,一种方法是使用 sys_brk 系统调用。它通过

int 0x80
EAX=45 访问。它在 EBX 中接受一个指针,代表新的堆顶。通常,堆区域的底部被初始化为刚好超出程序数据段的区域(内存中程序的上方)。要获得初始堆位置的地址,您可以调用 sys_break 并将 EBX 设置为 0。在系统调用之后,EAX 将是堆的当前基指针。当您需要访问堆内存或分配更多堆空间时,您可以将其保存起来。

此代码提供了一个示例,目的是为了清楚起见(而非性能),但可能是理解如何操作堆区域的起点:

SECTION .data
heap_base: dd 0          ; Memory address for base of our heap

SECTION .text
global _start
_start:
    ; Use `brk` syscall to get current memory address
    ; For the bottom of our heap This can be achieved
    ; by calling brk with an address (EBX) of 0
    mov eax, 45          ; brk system call
    xor ebx, ebx         ; don't request additional space, we just want to 
                         ; get the memory address for the base of our processes heap area.
    int 0x80
    mov [heap_base], eax ; Save the heap base

    ;Now allocate some space (8192 bytes)
    mov eax, 45          ; brk system call
    mov ebx, [heap_base] ; ebx = address for base of heap
    add ebx, 0x2000      ; increase heap by 8192 bytes
    int 0x80

    ; Example usage
    mov eax, [heap_base]      ; Get pointer to the heap's base
    mov dword [eax+0xFFF], 25 ; mov value 25 to DWORD at heapbase+0xFFF

    ;Exit the program
    mov eax, 1
    xor ebx, ebx
    int 0x80

1
投票

您没有不受限制的内存。此外,您不能不受限制地访问由 RAM 支持的地址空间部分。代码页映射为只读。作为 ring-3 程序,你不能自己改变它。

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