- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我尝试使用 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/
我想知道以下语句在 C 中会打印什么? printf("hello\n") || (printf("goodbye\n") || printf("world\n")); 我通常习惯于使用“cout”在
这是我目前正在学习的系统编程类(class)的幻灯片: catch_child 是 SIGCHLD 处理程序。输出与代码如何对应?为什么没有打印一些“Child #x started”消息? 最佳答案
这有点像拼图……我刚刚又回到了C,打算这次掌握它。所以我一直在阅读 The C Programming Language ,我得到了这个声明: Among others, printf also re
如何使用 printf 在字符串末尾附加空格? 我找不到任何在右侧附加空格的示例。 A similar question我发现使用 printf改为在字符串的左侧添加空格。 最佳答案 使用负数左对齐(
我想通过 usart 从 stm32f405 注销。 在我的 syscall.c 文件中,我实现了通过 usart 打印的功能: int _write(int file, char *ptr, int
我想定义一个记录器函数,比如 myPutStrLn = putStrLn . (++) "log: " main = do myPutStrLn "hello" 这很好。现在我想用 printf 格式
Printf module API详细介绍了类型转换标志,其中: %B: convert a boolean argument to the string true or false %b: conv
@H2CO3 这是我的主要代码: #pragma OPENCL EXTENSION cl_ amd_ printf : enable #define PROGRAM_FILE "matvec.cl"
Printf module API详细介绍了类型转换标志,其中: %B: convert a boolean argument to the string true or false %b: conv
您可以使用 printf 字段宽度说明符截断字符串: printf("%.5s", "abcdefgh"); > abcde 不幸的是,它不适用于数字(将 d 替换为 x 是相同的): printf(
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 4 年前。 Improve th
我遇到了我见过的最奇怪的错误之一。 我有一个简单的程序,可以打印多个整数数组。 对数组进行排序,然后打印...... place_in_buf(n100, 100); insertion(10
我的程序是每隔一段时间获取文件大小并显示它以记录任何更改。由于某种原因,执行下面的代码挂起,只为我提供了一个光标。没有打印或显示任何内容。 代码: #include #include #inclu
printf("It is currently %s's turn.\n", current->name); 我想知道为什么在 %s 之后打印出额外的换行符。我知道C 中的字符串总是以\0 结尾。没有
这个问题已经有答案了: printf anomaly after "fork()" (3 个回答) fork() in c using printf [duplicate] (2 个回答) 已关闭 9
我对编程很陌生。 我正在尝试编写一个程序,从数组中调用水果的价格。但我希望代码在写价格之前也写水果的名称。如果我键入 2,如何使输出为“Orange price : 10”而不仅仅是 price :
这个问题在这里已经有了答案: How do I print a non-null-terminated string using printf? (2 个答案) 关闭 7 年前。 例如,我有一个字符
我有一个 atmel UC3-L0 和罗盘传感器。现在我安装 AtmelStudio 并将一些演示代码下载到电路板中。但是我不知道演示代码中的函数 printf 会在哪里出现数据。我应该如何获取数据?
我有一个 atmel UC3-L0 和罗盘传感器。现在我安装 AtmelStudio 并将一些演示代码下载到电路板中。但是我不知道演示代码中的函数 printf 会在哪里出现数据。我应该如何获取数据?
嗨,我是 C 世界的新手,我的代码确实有些奇怪。目标是创建一个函数,可以在开头和结尾处用空格和/或制表符修剪字符串。我无法使用字符串库。 问题是我的代码中有一个 printf 只是用于测试,它的工作非
我是一名优秀的程序员,十分优秀!