gpt4 book ai didi

linux - printf 上的段错误 - NASM 64 位 Linux

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:28:37 25 4
gpt4 key购买 nike

我尝试使用 scanf 输入四个 float ,将它们存储到堆栈中,然后使用 vmovupd 将它们复制到寄存器以供使用。我的问题是当我尝试输出这 4 个数字时,程序在 printf 处出现段错误。

我认为它与堆栈有关,但我尝试弹出无数次(一次执行多条指令)但无济于事。我对汇编编码还是个新手,所以使用 gdb 对我来说有点太高级了。

您会注意到我包含了一个名为debug 的文件。它允许我查看寄存器和堆栈(这就是为什么有一个 dumpstack 指令。)这是我的教授提供的,它确实帮助了一些但显然还不够(或者也许我只是遗漏了一些东西) .

这是.cpp:

#include <iostream>

using namespace std;

extern "C" double ComputeElectricity();

int main()
{
cout << "Welcome to electric circuit processing by Chris Tarazi." << endl;
double returnValue = ComputeElectricity();
cout << "The driver received this number: " << returnValue << endl;
return 0;
}

这是 ASM 代码:

%include "debug.inc"
extern printf
extern scanf
global ComputeElectricity

;---------------------------------Declare variables-------------------------------------------

segment .data

greet db "This progam will help you analyze direct current circuits configured in parallel.", 10, 0
voltage db "Please enter the voltage of the entire circuit in volts: ", 0
first db "Enter the power consumption of device 1 (watts): ", 0
second db "Enter the power consumption of device 2 (watts): ", 0
third db "Enter the power consumption of device 3 (watts): ", 0
fourth db "Enter the power consumption of device 4 (watts): ", 0
thankyou db "Thank you. The computations have completed with the following results.", 10, 0
circuitV db "Curcuit total voltage: %1.18lf v", 10, 0
deviceNum db "Device number: 1 2 3 4", 10, 0
power db "Power (watts): %1.18lf %1.18lf %1.18lf %1.18lf", 10, 0
current db "Current (amps): %1.18lf %1.18lf %1.18lf %1.18lf", 10, 0
totalCurrent db "Total current in the circuit is %1.18lf amps.", 10, 0
totalPower db "Total power in the circuit is %1.18lf watts.", 10, 0

bye db "The analyzer program will now return total power to the driver.", 10, 0

string db "%s", 0
floatfmt db "%lf", 0
fourfloat db "%1.18lf %1.18lf %1.18lf %1.18lf", 0

;---------------------------------Begin segment of executable code------------------------------

segment .text

dumpstack 20, 10, 10

ComputeElectricity:

;dumpstack 30, 10, 10

;---------------------------------Output greet message------------------------------------------

mov qword rax, 0
mov rdi, string
mov rsi, greet
call printf

;---------------------------------Prompt for voltage--------------------------------------------

mov qword rax, 0
mov rdi, string
mov rsi, voltage
call printf

;---------------------------------Get voltage--------------------------------------------------

push qword 0
mov qword rax, 0
mov rdi, floatfmt
mov rsi, rsp
call scanf
vbroadcastsd ymm15, [rsp]
pop rax

;---------------------------------Prompt for watts 1--------------------------------------------

mov qword rax, 0
mov rdi, string
mov rsi, first
call printf

;---------------------------------Get watts 1---------------------------------------------------

push qword 0
mov qword rax, 0
mov rdi, floatfmt
mov rsi, rsp
call scanf

;---------------------------------Prompt for watts 2--------------------------------------------

mov qword rax, 0
mov rdi, string
mov rsi, second
call printf

;---------------------------------Get watts 2---------------------------------------------------

push qword 0
mov qword rax, 0
mov rdi, floatfmt
mov rsi, rsp
call scanf

;---------------------------------Prompt for watts 3--------------------------------------------

mov qword rax, 0
mov rdi, string
mov rsi, third
call printf

;---------------------------------Get watts 3---------------------------------------------------

push qword 0
mov qword rax, 0
mov rdi, floatfmt
mov rsi, rsp
call scanf

;---------------------------------Prompt for watts 4--------------------------------------------

mov qword rax, 0
mov rdi, string
mov rsi, fourth
call printf

;---------------------------------Get watts 4---------------------------------------------------

push qword 0
mov qword rax, 0
mov rdi, floatfmt
mov rsi, rsp
call scanf

;dumpstack 50, 10, 10

;---------------------------------Move data into correct registers------------------------------

vmovupd ymm14, [rsp] ; move all 4 numbers from the stack to ymm14

pop rax
pop rax
pop rax
pop rax

;dumpstack 55, 10, 10

vextractf128 xmm10, ymm14, 0 ; get lower half
vextractf128 xmm11, ymm14, 1 ; get upper half

;---------------------------------Move data into low xmm registers------------------------------

movsd xmm1, xmm11 ; move ymm[128-191] (3rd value) into xmm1
movhlps xmm0, xmm11 ; move from highest value from xmm11 to xmm0

movsd xmm3, xmm10
movhlps xmm2, xmm10

;showymmregisters 999

;---------------------------------Output results-------------------------------------------------

;dumpstack 60, 10, 10

mov rax, 4
mov rdi, fourfloat
push qword 0
call printf
pop rax

ret

最佳答案

问题出在您的堆栈使用上。

首先,ABI 文档要求 rsp 调用 之前是 16 字节对齐的。

由于 call 会将 8 字节的返回地址压入堆栈,因此您需要将 rsp 调整为 16 加 8 的倍数以返回到 16 字节结盟。 16 * n + 8 包括任何 push 指令或对 RSP 的其他更改,而不仅仅是 sub rsp, 24。这是段错误的直接原因,因为 printf 将使用对齐的 SSE 指令,这将导致未对齐的地址出错。

如果你解决了这个问题,你的堆栈仍然是不平衡的,因为你一直在压入值但从不弹出它们。很难理解你想用堆栈做什么。

通常的方法是在函数的开头(序言)为局部变量分配空间,并在结尾(结尾)释放它。如上所述,这个数量(包括任何推送)应该是 16 加 8 的倍数,因为函数 entry 上的 RSP(在调用者的 call 之后)距离 a 有 8 个字节16 字节边界。


在大多数 glibc 构建中,printf 只关心 AL != 0 时的 16 字节堆栈对齐。(因为这意味着有 FP args,所以它将所有 XMM 寄存器转储到堆栈以便它可以为它们编制索引以进行 %f 转换。)

即使它恰好在您的系统上工作,如果您使用未对齐的堆栈调用它仍然是一个错误; future 的 glibc 版本可能包括依赖于 16 字节堆栈对齐的代码,即使没有 FP args。例如,即使 AL=0 在大多数 GNU/Linux 发行版中,scanf 已经在未对齐的堆栈上崩溃。

关于linux - printf 上的段错误 - NASM 64 位 Linux,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25693827/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com