Memory management 程序集x86 brk()调用使用

Memory management 程序集x86 brk()调用使用,memory-management,assembly,x86-64,dynamic-memory-allocation,brk,x86,Memory Management,Assembly,X86 64,Dynamic Memory Allocation,Brk,X86,我试图将内存动态分配到堆中,然后在这些内存地址中分配值。我知道如何分配内存,但如何将寄存器中的值分配给第一个动态内存地址? 这就是我到目前为止所做的:` push rbp mov rbp, rsp ;initialize an empy stack to create activation records for the rest of the subroutines

我试图将内存动态分配到堆中,然后在这些内存地址中分配值。我知道如何分配内存,但如何将寄存器中的值分配给第一个动态内存地址? 这就是我到目前为止所做的:`

    push rbp
    mov rbp, rsp            ;initialize an empy stack to create activation records for the rest of the subroutines                                                                                                                        

    mov rax, 0x2d           ;linux system call for brk()                                                                                                                                                                                  
    mov rbx, 0x0            ;to get the adress of the first adress we are allocating we must have 0 in rbx                                                                                                                                
    int 0x80                ;calls the linux operating system kernel for assistance                                                                                                                                                       
    mov [brk_firstLocation], rax ;the first position in the heap will be returned in rax thus i save the first loaction in a varable called brk_firstLocation                                                                             

    mov rbx, rax            ;the memory adress of the start of the heap is moved in rbx                                                                                                                                                   
    add rbx, 0x14           ;we want 5 bytes worth of data alocated in the heap, so the start adress plus 20 bits                                                                                                                         
    mov rax, 0x2d           ;linux system call for brk()                                                                                                                                                                                  
    int 0x80                ;calls the linux operating system kernel for assistance
例如,我该怎么做才能将rax中的值移动到brk_firstLocation中


提前谢谢

如上所述,调用一次以检索当前堆的底部,然后移动堆的顶部(即brk值)。但是,您的代码在使用64位寄存器集时不正确
r.x
。如果您的Linux是32位的(使用45表示系统调用号),那么您需要设置32位寄存器:

mov eax, 45                            ; brk                                                                                                                                                                                  
mov ebx, 0                             ; arg 1: 0 = fail returning brk value in rax                                                                                                                               
int 0x80                               ; syscall
mov dword ptr [brk_firstLocation], rax ; save result
mov eax, 45                            ; brk                                                                                                                                                                                  
mov ebx, 4                             ; arg 1: allocate 4 bytes for a 32-bit int                                                                                                                                
int 0x80                               ; syscall

mov eax, dword ptr [brk_firstLocation] ; reload rax with allocated memory address.
mov dword ptr [eax], 42 ; use result: store 42 in newly allocated storage

当然,您可以重新加载保存的值,以便根据需要多次重复使用。

我发现有许多问题:

  • 0x2d是x86上的brk系统调用(32位);在x86_64上,它是0xc
  • brk设置数据段的结尾;成功时返回0,失败时返回-1。它不返回“堆中的第一个位置”。它来自链接器设置为未初始化预分配数据末尾的符号_end
所以你想要的是:

    mov [brk_firstloaction], _end
    mov rbx, [brk_firstlocation]
    add rbx, 0x14         ; space for 5 dwords (20 bytes)
    mov rax, 12
    int 0x80

int 80h
仅用于32位系统调用。将
syscall
改为64位

调用sys_brk两次是多余的-在汇编中,您总是知道程序数据的终点。只要在那里贴上标签,你就会知道地址

以这种方式分配少于一页的内存是没有意义的,它将以4KB的块进行分配


必须理解这一点-sys_brk不是堆管理功能。这是低级内存管理。

其他人指出了代码中的一些错误。我想补充的是,您不会向当前断点添加20位(或者像
addrbx这样的20个字节,实际上是20个),您只需添加5个字节即可

此外,您的第一个syscall参数将不在rbx中,而是在rdi中。使用不同的系统调用号、不同的寄存器和不同的指令(
syscall
而不是
int 0x80
),而不是32位ABI(在64位进程中仍然可用)。有关更多ABI链接,请参见标记wiki

下面是代码的外观:

push rbp
mov rbp, rsp

;; sys_brk(0)
mov   rax, 12         ; 12 is SYS_brk (/usr/include/asm/unistd_64.h)
mov   rdi, 0          ; rdi for first syscall arg in the 64-bit ABI, not rbx
syscall               ; syscall, not int 0x80, for the 64-bit ABI

mov   qword [brk_firstLocation], rax

;; sys_brk(old_break + 5)
lea   rdi, [rax + 5]  ; add 5 bytes to the break point
mov   rax, 12
syscall               ; set the new breakpoint

此时,您可以使用brk_firstLocation作为指向要存储在堆上的任何5字节结构的指针。下面是如何将值放入该内存空间:

mov   rdi, [brk_firstLocation]   ; load the pointer from memory, if you didn't already have it in a register

mov   byte [rdi], 'A'            ; a char at it's first byte
mov   [rdi+1], ecx               ; a 32-bit value in the last 4 bytes.

这里的32位
int0x80
和64位
syscall
内核调用之间是否仍然存在混淆?OP正在编写64位代码,因此使用64位系统调用ABI对于涉及指针的系统调用是必不可少的。它与i386 ABI(仍然可用于64位进程)完全不同。可能sys_brk的C包装器返回0或-1。这是系统调用的常见情况。参考:即使在64位进程中,实际的系统调用也确实返回新内存区域的结尾或当前结尾(如果参数为0)。OP需要
eax=12
/
syscall
,第一个参数为
rdi
。另请参见。在哪里可以找到有关_结束符号的更多信息?有我可以参考的符号列表吗?brk内存区域不是在程序结束后立即出现的,它是随机的。最后,使用64位系统调用ABI并正确使用它的答案。()我修复了几个简单但严重的错误;我认为这是完全正确的(也是这个问题唯一正确的答案)。