Ошибка сегментации доступа к памяти x86

Из любопытства изучаю сборку 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 даст мне неограниченный доступ к виртуальному адресному пространству моего процесса. Разве это не так?

Как бы вы реализовали что-то вроде кучи в сборке?

2 ответа

Решение

В Linux(x86) - хотя у вас есть виртуальный диапазон адресов 4 ГБ в вашем процессе, не все из них доступны. Верхний 1 ГБ - это то место, где находится ядро, и есть области с нехваткой памяти, которые нельзя использовать. Адрес виртуальной памяти 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

У вас нет неограниченной оперативной памяти. Кроме того, у вас нет неограниченного доступа к той части вашего адресного пространства, которая поддерживается RAM. Кодовые страницы отображаются только для чтения. И как программа ring-3, вы не можете изменить это самостоятельно.

Другие вопросы по тегам