c++ - 为什么我收到错误:中断服务例程应该将“unsigned long int”作为第二个参数?
问题描述
我收到一个简单的错误,因为我阅读了一份文档(https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#x86-Function-Attributes)并且想要正确地做事。在本文件中指出:
必须使用强制指针参数声明中断处理程序:
struct interrupt_frame; __attribute__ ((interrupt)) void f (struct interrupt_frame *frame) { }
并且您必须按照处理器手册中的说明定义 struct interrupt_frame。
异常处理程序与中断处理程序不同,因为系统将错误代码压入堆栈。异常处理程序声明类似于中断处理程序,但具有不同的强制函数签名。编译器安排在 IRET 指令之前将错误代码从堆栈中弹出。
#ifdef __x86_64__ typedef unsigned long long int uword_t; #else typedef unsigned int uword_t; #endif struct interrupt_frame; __attribute__ ((interrupt)) void f (struct interrupt_frame *frame, uword_t error_code) { ... }
异常处理程序应该只用于推送错误代码的异常;在其他情况下,您应该使用中断处理程序。如果使用了错误类型的处理程序,系统将崩溃。
因此,推送错误代码的异常应具有 64 位长作为第二个参数。其他应该只有用户定义的 interrupt_frame 结构。因此,我尝试使用以下代码来做到这一点:
struct InterruptFrame{
UINT64 rsp;
};
//Divide by zero error
__attribute__((interrupt)) void IDT::isr0(InterruptFrame* frame) {
asm volatile("hlt");
}
//Page fault
__attribute__((interrupt)) void IDT::isr14(InterruptFrame* frame, unsigned long long int errorCode) {
asm volatile("hlt");
}
这些只是示例,因为我有更多独立的 ISR。当我编译时
g++ -static -ffreestanding -nostdlib -mgeneral-regs-only -mno-red-zone -c -m64 Kernel/Source/IDT.cpp -oKernel/Object/IDT.o
我收到一条错误消息
error: interrupt service routine should have ‘unsigned long int’ as the second argument
即使我完全按照文档中的说明做了。即使对于当前具有 unsigned long long int 作为第二个参数的页面错误处理程序,我也会收到每个 ISR 的错误。我在网上没有找到太多关于错误的搜索,所以我想在这里问。
怎么了?此外,对于 x86-64,InterruptFrame 结构应该包含哪些成员?
解决方案
最后,这个问题是我的一个小错误。我__attribute__((interrupt))
在 C++ IDT 成员函数的声明上而不是在原型上声明了。您可以使用以下内容重现该问题:
struct InterruptFrame{
unsigned long rsp;
};
class IDT{
public:
static void isr0(InterruptFrame* frame);
static void isr14(InterruptFrame* frame, unsigned long errorCode);
};
__attribute__((interrupt)) void IDT::isr0(InterruptFrame* frame) {
asm volatile("hlt");
}
__attribute__((interrupt)) void IDT::isr14(InterruptFrame* frame, unsigned long errorCode) {
asm volatile("hlt");
}
此文件产生错误。而以下文件不会产生任何错误。
struct InterruptFrame{
unsigned long rsp;
};
class IDT{
public:
__attribute__((interrupt)) static void isr0(InterruptFrame* frame);
__attribute__((interrupt)) static void isr14(InterruptFrame* frame, unsigned long errorCode);
};
void IDT::isr0(InterruptFrame* frame) {
asm volatile("hlt");
}
void IDT::isr14(InterruptFrame* frame, unsigned long errorCode) {
asm volatile("hlt");
}
我可以反汇编代码,看看中断代码似乎是正确的:
user@user-System-Product-Name:~$ objdump -d test.o
test.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <_ZN3IDT4isr0EP14InterruptFrame>:
0: f3 0f 1e fa endbr64
4: 55 push %rbp
5: 48 89 e5 mov %rsp,%rbp
8: 50 push %rax
9: 48 83 ec 08 sub $0x8,%rsp
d: 48 8d 45 08 lea 0x8(%rbp),%rax
11: 48 89 45 f0 mov %rax,-0x10(%rbp)
15: f4 hlt
16: 90 nop
17: 48 83 c4 08 add $0x8,%rsp
1b: 58 pop %rax
1c: 5d pop %rbp
1d: 48 cf iretq
1f: 90 nop
0000000000000020 <_ZN3IDT5isr14EP14InterruptFramem>:
20: f3 0f 1e fa endbr64
24: 55 push %rbp
25: 48 89 e5 mov %rsp,%rbp
28: 50 push %rax
29: 48 83 ec 10 sub $0x10,%rsp
2d: 48 8d 45 10 lea 0x10(%rbp),%rax
31: 48 89 45 f0 mov %rax,-0x10(%rbp)
35: 48 8b 45 08 mov 0x8(%rbp),%rax
39: 48 89 45 e8 mov %rax,-0x18(%rbp)
3d: f4 hlt
3e: 90 nop
3f: 48 83 c4 10 add $0x10,%rsp
43: 58 pop %rax
44: 5d pop %rbp
45: 48 83 c4 08 add $0x8,%rsp
49: 48 cf iretq
我仍然想知道为什么中断代码不推送所有寄存器?
推荐阅读
- javascript - 对象作为 React 子对象无效(找到:带有键 {..} 的对象)。.....改用数组。在 Select(由 Context.Consumer 创建)
- sql - 用第二个表中的名称替换同一表中 2 列中的 id
- c# - 是否有在 revit api c# 2021 中使用 ParameterSplit 的替代方法?
- javascript - 即使使用 createElementNS 也不会出现动态添加的 SVG 元素
- python - 为什么即使安装了所有东西,谷歌 colab 仍显示缺少模块/包?
- javascript - 设置变体选项数组时出错无法读取未定义的属性“0”
- generative-adversarial-network - 关于辅助分类生成对抗网络 ACGAN,您有什么改进建议
- excel - 查找在特定日期范围内出现的人
- javascript - 当应用程序终止时,EXPO BackgoroundFecth 对 android 应用程序的依赖是否仍将在后台工作?
- javascript - Mongodb位置运算符不起作用