NASM 64bit中的分段故障

时间:2014-08-25 01:02:36

标签: c++ linux assembly segmentation-fault nasm

我尝试从scanf获得3个输入后将结果输出给用户。

当我运行我的代码时,我能够获得所需的输入。然而,在我收集输入并开始计算后它会崩溃。

顺便说一句,我使用的是带有g ++和NASM 64bit的Ubuntu 14.04。

以下是应该的样子:

This program is brought to you by Chris Tarazi

Welcome to Areas of Trapezoids

Please enter one of the base numbers: 5.8

Please enter the other base number: 2.2

Please enter the height: 6.5

****//Crashes here with Segmentation fault (core dumped)****

The area of a trapezoid with sizes 5.799999999999999365, 2.200000000000000153, 
and 6.500000000000000000 is 26.000000000000000328

Have a nice day.  Enjoy your trapezoids.

C++档案:

#include <stdio.h>
#include <stdint.h>

extern "C" double ComputeArea();    // links with global in assembly

using namespace std;

int main()
{
    double area;

    printf("This program is brought to you by Chris Tarazi.\n");

    area = ComputeArea();

    printf("Have a nice day. Enjoy your trapezoids.\n");

    return 0;
}

装配文件:

extern printf                                               ; This function will be linked later.

extern scanf

global ComputeArea                                          ; Declare function global to link with "extern" from C++.   

;---------------------------------Declare variables-------------------------------------------
segment .data

welcome:                           db "Welcome to the area of trapezoids.", 10, 0

input:                             db "Please enter one of the base numbers: ", 0

secInput:                          db "Please enter the other base number: ", 0

output:                            db "The area of a trapezoid with sizes %1.18lf, %1.18lf, and %1.18lf is %1.18lf .", 10, 0

hInput:                            db "Please enter the height: ", 0

inputformat:                       db "%lf", 0

stringformat:                      db "%s", 0

fourfloatformat:                   db "%1.18lf  %1.18lf  %1.18lf  %1.18lf", 0                                                 


;---------------------------------Begin segment of executable code------------------------------
segment .text

ComputeArea:                                                    ; Area of trapezoid = ((a + b) / 2) * h.

    push       rbp                                              ; Save a copy of the stack base pointer
    mov        rbp, rsp                                         ; We do this in order to be 100% compatible with C and C++.
    push       rbx                                              ; Back up rbx
    push       rcx                                              ; Back up rcx
    push       rdx                                              ; Back up rdx
    push       rsi                                              ; Back up rsi
    push       rdi                                              ; Back up rdi
    push       r8                                               ; Back up r8
    push       r9                                               ; Back up r9
    push       r10                                              ; Back up r10
    push       r11                                              ; Back up r11
    push       r12                                              ; Back up r12
    push       r13                                              ; Back up r13
    push       r14                                              ; Back up r14
    push       r15                                              ; Back up r15
    pushf                                                       ; Back up rflags

;---------------------------------Output messages to user---------------------------------------
    mov qword rax, 0
    mov rdi, stringformat
    mov rsi, welcome
    call printf

    mov qword rax, 0
    mov rdi, stringformat
    mov rsi, input
    call printf

    push qword 0
    mov qword rax, 0  
    mov rdi, inputformat
    mov rsi, rsp                ;firstbase
    call scanf
    movsd xmm0, [rsp]
    pop rax

    mov qword rax, 0
    mov rdi, stringformat
    mov rsi, secInput
    call printf

    push qword 0
    mov qword  rax, 0  
    mov rdi, inputformat
    mov rsi, rsp                ;secondbase
    call scanf
    movsd xmm1, [rsp + 4]
    pop rax

    mov qword rax, 0
    mov rdi, stringformat
    mov rsi, hInput
    call printf

    push qword 0
    mov qword  rax, 0  
    mov rdi, inputformat
    mov rsi, rsp                ;height
    call scanf
    movsd xmm2, [rsp + 8]
    pop rax

;---------------------------------Begin ComputeArea Calculation-----------------------------------

    mov rax, 2
    cvtsi2sd xmm3, rax

    addsd xmm0, xmm1
    divsd xmm0, xmm3
    mulsd xmm0, xmm2

    ret

;---------------------------------Output result to user-------------------------------------------
    mov rax, 3
    mov rdi, output
    call printf

1 个答案:

答案 0 :(得分:1)

首先,为什么你要保存那些寄存器的全部?!? 64位Linux的ABI表示,如果在函数中使用这些寄存器,则只需要保存rbxrbpr12 - r15。另外,你使用Assembler,不需要在64bit的地方创建一个堆栈帧(加上你甚至不使用rbp!所以为什么要创建一个堆栈帧?)唯一非常重要的是为确保您的堆栈在16字节边界上对齐 - 调用将推送一个8字节的返回地址,因此您的ComputeArea函数所需要的只是sub rsp, 8add rsp, 8

在您使用scanf的第一个rsp中,如果没有调整它,您只是覆盖了一些内容!

你在这里做一些计算:

mov rax, 2
cvtsi2sd xmm3, rax

addsd xmm0, xmm1
divsd xmm0, xmm3
mulsd xmm0, xmm2

ret

你从这里的程序返回,但不要弹出你刚刚推送的所有寄存器!!所以基本上你的堆栈指针都搞砸了! CPU不知道返回地址是什么!

你在序言中所做的事情,必须在你回来之前在结语中逆转!

也许,你应该开始简单,阅读3个花车并尝试打印它们!

当我更正你的代码时,这是我的输出:

Welcome to the area of trapezoids.
Please enter one of the base numbers: 5.8
Please enter the other base number: 2.2
Please enter the height: 6.5
The area of a trapezoid with sizes 5.799999999999999822, 2.200000000000000178, and 6.500000000000000000 is 26.000000000000000000 .