【问题标题】:How to use malloc in asm如何在 asm 中使用 malloc
【发布时间】:2020-04-29 01:03:03
【问题描述】:

我正在尝试使用 malloc 在带有 nasm 的 asm Intel x86_64 中动态分配内存,但我不明白如何使用它。

例如,如果你想分配一个 8 字节的内存区域,我应该将 8 压入堆栈然后调用 malloc,像这样吗?

extern _malloc

section .text
    global _my_function

_my_function:
    push 20
    call _malloc
    ret

或者我应该将 20 移到 rdi 寄存器,这通常是函数的第一个参数吗?

extern _malloc

section .text
    global _my_function

_my_function:
    mov rdi, 20
    call _malloc
    ret

我都试过了,但都没有奏效,而且我没有找到任何 nasm 的 malloc 文档。

我正在尝试使用 malloc 来重新编码字符串库中的 strdup 函数,这是我的实际代码:

extern _ft_strlen
extern _ft_strcpy
extern _malloc

section .text
    global _ft_strdup

_ft_strdup:
    push rsi
    push rdi                ; rdi = str
    call _ft_strlen         ; rax = ft_strlen(str)
    mov r9, rdi             ; save rdi (str) into r9
    mov rdi, rax            ; rdi = len
    inc rdi                 ; rdi = len + 1
    call _malloc            ; rax = new_str (allocated)
    cmp eax, 0              ; if malloc failed
    je _failure             ; └──► return NULL
    mov rsi, r9             ; rsi = str
    mov rdi, rax            ; rdi = new_str
    call _ft_strcpy         ; ft_strcpy(new_str, str)
    pop rdi
    pop rsi
    ret

_failure:
    xor rax, rax
    pop rdi
    pop rsi
    ret
section .text
    global _ft_strcpy

_ft_strcpy:
    push rdi
    push rsi
    jmp _loop

_loop:
    mov r8b, BYTE [rdi]     ; Save *dst into r8b
    mov r9b, BYTE [rsi]     ; Save *src into r8b
    cmp r9b, 0              ; if *src == '\0'
    je finish               ; └──► exit from _loop
    mov [rdi], r9           ; *dst = r9 (r9 = *src)
    inc rdi                 ; dst++
    inc rsi                 ; src++
    jmp _loop

finish:
    mov [rdi], r9           ; *dst = r9 (r9 = *src = '\0')
    pop rsi
    pop rdi
    mov rax, rdi            ; rax = initial value of dst
    ret                     ; Return rax (dst pointer)
section .text
    global _ft_strlen

_ft_strlen:
    push rdi
    xor rax, rax            ; rax = 0
    jmp _loop

_loop:
    cmp [rdi], byte 0       ; if *str == '\0'
    je finish               ; └──► exit from _loop
    inc rax                 ; rax++ (len)
    inc rdi                 ; str++
    jmp _loop

finish:
    pop rdi
    ret                     ; Return rax (len)

当我调用 ft_strdup 时,我收到来自 sanitize 的 SEGV on unknown address 0x000000000000 错误。

我这样调用函数:

int main(int ac, char **av)
{
    char new_str = ft_strdup(av[1]);
    return (0);
}

【问题讨论】:

  • 是的,将所有代码显示为minimal reproducible example。还可以使用调试器查明错误并回溯到导致错误的原因。也就是说,mov rdi, 20; call _malloc 应该没问题。请注意,返回值在rax 中,而不仅仅是eax,所以对于NULL,您必须进行测试(但这不是问题的原因)。也不清楚mov rax, r12 应该做什么。此外,根据标准调用约定rdi 是调用者保存的,因此您不能在_ft_strlen 之后依赖它的值。在您致电_malloc 时,r9 也是如此,这可能是您的问题。
  • 哦,对了,我忘了删除mov rax, r12声明,我的错,让我编辑帖子添加其他功能
  • 您为什么操作系统编程?请添加适当的标签。
  • @fuz 为什么会这样?在我看来是正确的。它也有效。正如我所说,问题是malloc 破坏了他用来保存字符串指针的r9
  • 是的,是的!你可以发布答案!我刚刚在 _malloc 调用之前添加了一个 push r9 语句,在它之后添加了一个 pop r9,它起作用了

标签: macos assembly x86-64 nasm


【解决方案1】:

解决方案 - jester

带有 nasm 的 Intel x86_64 的 Malloc 使用

  • 要 malloc 的字节进入 rdi 寄存器。
  • 返回指向rax 寄存器中内存区域的指针。
mov rdi, 20
call _malloc

根据standard calling convention,您在调用_ft_strlen 后不能依赖rdi 的值,在调用_mallocr9 也是如此。这是因为两个寄存器都是caller-saved

为了保留r9的值

push r9
call _malloc
pop r9

汇编编程技巧

【讨论】:

  • 请注意,ABI 要求 RSP 在 call 之前对齐 16 字节。在 else-equal 函数中,单个 push 会使堆栈错位。通常,编译器会在函数入口处保留一次空间,以使用 mov 溢出/重新加载内容,而不是在单个调用时使用 push/pop。如果你想让一个值在调用中存活下来,通常你只需将它保存在像 RBX 或 R15 这样的调用保留寄存器中(你在整个函数中保存/恢复一次,而不是在函数内每次调用一次)跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-17
  • 1970-01-01
  • 2021-02-20
  • 2020-08-26
相关资源
最近更新 更多