我出于好奇而学习x86汇编。我目前正在使用带有NASM汇编器的基于Linux的操作系统。我很难理解为什么
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(x86)上-尽管您的进程中的虚拟地址范围为4gb,但并非所有虚拟地址都可以访问。较高的1gb是内核所在的位置,并且有一些内存不足的区域无法使用。虚拟内存地址0xfff不能被写入或读取(默认情况下),因此您的程序会因段错误而崩溃。
在后续评论中,您建议您打算在汇编程序中创建堆。可以做到,一种方法是使用 sys_brk 系统调用。通过int 0x80和 EAX = 45 访问。它在 EBX中使用 一个指针来表示堆的新顶部。通常,堆区域的底部被初始化为刚好位于程序数据段之外(内存中程序上方)的区域。要获取初始堆位置的地址,可以在 EBX 设置为0的情况下调用 sys_break 。在系统调用之后, EAX 将成为堆的当前基本指针。当您需要访问堆内存或分配更多堆空间时,可以节省下来。
int 0x80
这段代码提供了一个示例,目的是为了清楚(而不是性能),但可能是理解如何操作堆区域的起点:
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