我正在编写一个小型 x86-64 内核。我正在设置 IDT 并遇到了一个我不太明白的奇怪错误。这是一个最小的例子:
entry.s
extern InterruptHandler
global isr0
align 4
isr0:
jmp sharedisr
sharedisr:
push rax
push rbx
push rcx
push rdx
push rdi
push rsi
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
cld
call InterruptHandler
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rsi
pop rdi
pop rdx
pop rcx
pop rbx
pop rax
iretq
idt.cpp
#include "idt.h"
struct IDTEntry{
unsigned short offset0; //bits 0-15
unsigned short selector; //0x08 = 1000b code selector
unsigned char ist; //0
unsigned char attrib; //
unsigned short offset1; //bits 16-31
unsigned int offset2; //bits 31-63
unsigned int zero; //0
}__attribute__((packed));
struct IDTR{
unsigned short size;
unsigned long address;
}__attribute__((packed));
unsigned long isrAddresses[1];
IDTEntry idt[1];
extern "C" void InterruptHandler(){
}
void SetupIDT(){
isrAddresses[0] = {
(unsigned long)&isr0
};
IDTEntry entry;
for (unsigned int i = 0; i < 1; i++){
entry.offset0 = (unsigned short)isrAddresses[i];
entry.selector = 0x08;
entry.ist = 0;
entry.attrib = 0x8e;
entry.offset1 = (unsigned short)(isrAddresses[i] >> 16);
entry.offset2 = (unsigned int)(isrAddresses[i] >> 32);
entry.zero = 0;
idt[i] = entry;
}
unsigned long idtAddr = (unsigned long)idt;
IDTR idtr = { 4096, idtAddr };
unsigned long idtrAddr = (unsigned long)&idtr;
asm volatile("lidt (%0)" : : "r"(idtrAddr));
}
idt.h
#ifndef IDTH
#define IDTH
extern "C" void isr0(void);
void SetupIDT();
#endif
main.cpp
#include "idt.h"
void main(){
SetupIDT();
asm volatile("hlt");
}
我用这个 bash 脚本编译并链接:
nasm entry.s -felf64 -oentry.o
g++ -static -ffreestanding -nostdlib -mgeneral-regs-only -mno-red-zone -c -m64 main.cpp -omain.o
g++ -static -ffreestanding -nostdlib -mgeneral-regs-only -mno-red-zone -c -m64 idt.cpp -oidt.o
ld -entry main --oformat elf64-x86-64 --no-dynamic-linker -static -nostdlib -Ttext-segment=ffff800001000000 entry.o main.o idt.o -okernel.elf
我收到错误ld: failed to convert GOTPCREL relocation; relink with --no-relax
。如果我添加--no-relax
ld 的选项它有效并且代码实际上有效。我可以在 InterruptHandler 函数中打印一些内容并返回到触发异常的先前代码(我测试了它在故意引发的除以零的情况下工作)。
从错误中我猜想这与链接松弛有关,但我不知道它是什么。有人可以简要解释一下它是什么以及为什么我会收到错误吗?另外,任何人都可以就建立适当的 ISR 提供任何进一步的建议吗?例如,我应该推送 RBP 然后将 RSP 放入 RBP 中,就像 gcc 在使用时所做的那样__attribute__((interrupt))
? ISR 末尾是否还应该有一个leaveq? ETC...
谢谢您的任何提示!