好奇心,我正在学习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构build一个程序会让我无限制地访问我的进程的虚拟地址空间。 不是这样吗?
你将如何在组装中实现像堆一样的东西?
在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
你没有不受限制的RAM。 此外,您不能无限制访问由RAM支持的地址空间部分。 代码页映射为只读。 而作为一个三环节目,你不能自己改变。