使用mul第二次后的分段错误

时间:2017-03-02 15:41:51

标签: assembly nasm

我在Assembly中总是noob,我尝试创建函数并在C中使用它。这个函数得到3个变量a,x,y是包含两个64位int的结构。我想要返回+ x * y。不幸的是,这段代码是NASM导致的一个段错误

%define a1 [rdi]
%define a2 [rdi+8]
%define x1 [rsi]
%define x2 [rsi+8]
%define y1 [rdx]
%define y2 [rdx+8]
%define output1 rax
%define output2 rdx
%define res1 r8
%define res2 r9

global abc

abc:

mov output1, x1
mul qword y1
mov res1, output1
mov output1, x1
mul qword y2
mov res2, output1
mov output1, x2
mul qword y1
add res2, output1
mov output1, res1
mov output2, res2


ret

使用第二个和第三个mul删除行允许我运行我的程序而不会出现段错误。

1 个答案:

答案 0 :(得分:0)

如果你解开上面的宏定义,你最终会得到这个,这就是处理器实际上试图执行的内容:

mov rax, [rsi]
mul qword [rdx]      <--- no segfault here
mov r8, rax
mov rax, [rsi]
mul qword [rdx+8]    <--- segfault here
mov r9, rax
mov rax, [rsi+8]
mul qword [rdx]      <--- segfault here
add r8, rax
mov rax, r8
mov rdx, r9

你说分段错误发生在上面标记的行上。

让我们做一点心理调试(Raymond Chen最喜欢的调试之一)。考虑第一个mul指令后发生的情况:rax设置为产品的低部分,rdx设置为产品的高部分。

这意味着在第一个mul之后,rdx发生了变化!它不再是指向y1y2的指针,而是与x1 * y1导致的任何内容有关。在此之后的任何连续尝试都使用rdx作为指针保证失败,因为它不再是一个。

因此,为了解决这个问题,您必须在另一个寄存器中的乘法中保留rdx。此代码未使用r10,并且它被视为易失性,因此我们可以安全地使用它来存储初始值rdx的“备份”。所以这样的事情可能足以解决它:

%define a1 [rdi]
%define a2 [rdi+8]
%define x1 [rsi]
%define x2 [rsi+8]
%define y1 [r10]         ; Change which register we're using as the
%define y2 [r10+8]       ; pointer to 'r10'.
%define output1 rax
%define output2 rdx
%define res1 r8
%define res2 r9

global abc

abc:
    mov r10, rdx         ; Preserve the real pointer to 'y1' in 'r10'.

    mov output1, x1
    mul qword y1
    mov res1, output1
    mov output1, x1
    mul qword y2
    mov res2, output1
    mov output1, x2
    mul qword y1
    add res2, output1
    mov output1, res1
    mov output2, res2

    ret
相关问题