【问题标题】:x86_64 assembly string manipulation causes segmentation faultx86_64 程序集字符串操作导致分段错误
【发布时间】:2020-02-05 13:09:47
【问题描述】:

我正在尝试在汇编中编写一个“strcat”函数,但无法获取我传递给它以更改的内存中的值。我的测试崩溃了,我不明白为什么。我似乎也无法以易于理解的方式找到有关 x86_64 程序集的任何好的文档。

    global  _ft_strcat

_ft_strcat:
        push    rbx
        push    rdx
        mov     rbx, rsi
        mov     rdx, rdi
parse:
        cmp     byte [rdx], 0
        je      concat
        inc     rdx
        jmp     parse
concat:
        cmp     BYTE[rbx], 0
        je      finish
        mov     dl, BYTE[rbx]
        mov     BYTE[rdx], dl
        inc     rdx
        inc     rbx
        jmp     concat
finish:
        mov     BYTE[rdx], 0
        mov     rax, rdi
        pop     rdx
        pop     rbx
        ret

上面是我要写的函数,下面是我的测试。

int             main(void)
{
        char    buffer[50] = "Hello, ";
        ft_strcat(buffer, "World!");
        printf("%s\n", buffer);
        return (0);
}

我遗漏了诸如包含和标题之类的内容,因为从我所看到的情况来看,这与问题无关。我通过调试器运行它,并注意到在我的函数结束时,rdi 寄存器指向的字符串没有改变,但我确实通过了 concat 标签中的循环,它看起来像是从字符串中提取的值rsi 所指向的确实是被复制到了 dl 寄存器中。

【问题讨论】:

    标签: c macos assembly x86-64 nasm


    【解决方案1】:

    您的推送和弹出不匹配,因此您的例程更改 rbprbx 违反了 ABI 保留它们的要求。

    【讨论】:

    • 非常感谢您。我会更新问题...我没有注意到那个错误...谢谢
    【解决方案2】:

    我的问题是我不了解我是如何操作 rdx 寄存器的最低 8 位的。通过将我的字符插入 dl,它的值更新了 rdx 的整体值,这意味着我实际上并没有连接我拥有的字符串,但我正在写入我不知道我正在写入的内存区域。

    代码现在看起来像这样

        global  _ft_strcat
    
    _ft_strcat:
            push    rbx
            push    rdx
            push    rcx
            xor     rcx, rcx
            mov     rbx, rsi
            mov     rdx, rdi
    parse:
            cmp     byte [rdx], 0
            je      concat
            inc     rdx
            jmp     parse
    concat:
            cmp     BYTE[rbx], 0
            je      finish
            mov     cl, BYTE[rbx]
            mov     BYTE[rdx], cl
            inc     rdx
            inc     rbx
            jmp     concat
    finish:
            mov     BYTE[rdx], 0
            pop     rcx
            pop     rdx
            pop     rbx
            mov     rax, rdi
            ret
    

    您会注意到添加了 Rex 寄存器并使用它的低 8 位来复制字节。

    【讨论】:

    • 您可以在 x86-64 SysV 调用约定中破坏 RDX、RCX、RAX、RSI、RDI 和 R8-R11。您不需要推送/弹出保存/恢复它们。如果您避免使用 RBX,则不需要任何推送/弹出。您还可以通过将条件分支放在循环底部来保存指令,例如 inc / cmp/jne parse 就像普通的 asm 循环一样。不过,这确实需要注意避免一个错误。
    猜你喜欢
    • 1970-01-01
    • 2016-08-07
    • 2020-03-20
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    • 2013-05-26
    • 1970-01-01
    • 2019-08-21
    相关资源
    最近更新 更多