nasm 宏无法正常工作
nasm macro doesn't work properly
我正在尝试设置我的内核的 IDT,但我收到这个 linking 错误:
bin/obj/idt.o: In function `setup_idt':
idt.c:(.text+0x9b): undefined reference to `interrupt_handler_1'
错误说 interrupt_handler_1 未定义,但它是 interrupt_manager.asm 中的一个宏:
%macro no_error_code_interrupt_handler 1
global interrupt_handler_%1
interrupt_handler_%1:
cli
push dword 0 ; push 0 as error code
push dword %1 ; push the interrupt number
jmp common_interrupt_handler ; jump to the common handler
%endmacro
这里是 setyup_idt 函数:
extern void interrupt_handler_1();
void setup_idt()
{
// Set the special idt_pointer
idt_pointer.limit = ( sizeof(struct InterruptDescriptorTableEntry) * 256 ) - 1; // Subsract 1 because sizeof doesn't start from 0
idt_pointer.address = (uint32)&idt;
// Clear the whole idt to zeros
memset(&idt, 0, sizeof(struct InterruptDescriptorTableEntry) * 256 );
for(unsigned int i = 0; i < 256; i++)
{
idt_set_gate(i, (uint32)&interrupt_handler_1, 0x8, 0x8E);
}
__asm__ __volatile__("lidt %0": :"m"(idt_pointer));
}
我哪里做错了?
额外的问题:有没有 macro/another 方法自动 link GDT 的第 i 个入口到第 i 个中断处理程序,让我试着更好地解释一下自己:
我想做的是这样的:
for(unsigned int i = 0; i < 256; i++)
{
idt_set_gate(i, (uint32)&interrupt_handler_[i], 0x8, 0x8E);
}
其中 interrupt_handler[i] 将是中断处理程序_[i] 将被 nasm 宏替换
您需要在 NASM 代码中展开宏。宏定义本身不生成任何代码。它需要在 NASM 代码中明确使用。
您可以使用%rep
指令重复扩展具有不同参数的宏。像这样:
extern common_interrupt_handler
%macro error_code_interrupt_handler 1
global interrupt_handler_%1
interrupt_handler_%1:
push dword %1 ; push the interrupt number
jmp common_interrupt_handler ; jump to the common handler
%endmacro
%macro no_error_code_interrupt_handler 1
global interrupt_handler_%1
interrupt_handler_%1:
push dword 0 ; push 0 as error code
push dword %1 ; push the interrupt number
jmp common_interrupt_handler ; jump to the common handler
%endmacro
; Some CPU exceptions have error codes, some don't
%assign intnum 0
%rep 8 - intnum
no_error_code_interrupt_handler intnum
%assign intnum intnum + 1
%endrep
error_code_interrupt_handler 8
no_error_code_interrupt_handler 9
%assign intnum 10
%rep 16 - intnum
error_code_interrupt_handler intnum
%assign intnum intnum + 1
%endrep
no_error_code_interrupt_handler 16
error_code_interrupt_handler 17
no_error_code_interrupt_handler 18
no_error_code_interrupt_handler 19
no_error_code_interrupt_handler 20
%assign intnum 21 ; first (currently) unassigned CPU exception
%rep 32 - intnum
no_error_code_interrupt_handler intnum
%assign intnum intnum + 1
%endrep
%assign intnum 32 ; first user defined interrupt
%rep 256 - intnum
no_error_code_interrupt_handler intnum
%assign intnum intnum + 1
%endrep
; define a table of interrupt handlers for C code to use
global interrupt_handler_table
interrupt_handler_table:
%assign intnum 0
%rep 256
dd interrupt_handler_ %+ intnum
%assign intnum intnum + 1
%endrep
上面的代码创建了一个 table 的所有中断处理程序,您可以像这样在 C 代码中使用它们:
extern uint32 interrupt_handler_table[256];
for(unsigned int i = 0; i < 256; i++)
{
idt_set_gate(i, interrupt_handler_table[i], 0x8, 0x8E);
}
请注意,我已经为那些确实会生成错误代码的 CPU 异常创建了一个 error_code_interrupt_handler
宏。此外,我已经从您的代码中删除了不必要的 CLI 指令。由于您在 IDT 中使用中断门,因此中断启用标志会自动清除。
我正在尝试设置我的内核的 IDT,但我收到这个 linking 错误:
bin/obj/idt.o: In function `setup_idt':
idt.c:(.text+0x9b): undefined reference to `interrupt_handler_1'
错误说 interrupt_handler_1 未定义,但它是 interrupt_manager.asm 中的一个宏:
%macro no_error_code_interrupt_handler 1
global interrupt_handler_%1
interrupt_handler_%1:
cli
push dword 0 ; push 0 as error code
push dword %1 ; push the interrupt number
jmp common_interrupt_handler ; jump to the common handler
%endmacro
这里是 setyup_idt 函数:
extern void interrupt_handler_1();
void setup_idt()
{
// Set the special idt_pointer
idt_pointer.limit = ( sizeof(struct InterruptDescriptorTableEntry) * 256 ) - 1; // Subsract 1 because sizeof doesn't start from 0
idt_pointer.address = (uint32)&idt;
// Clear the whole idt to zeros
memset(&idt, 0, sizeof(struct InterruptDescriptorTableEntry) * 256 );
for(unsigned int i = 0; i < 256; i++)
{
idt_set_gate(i, (uint32)&interrupt_handler_1, 0x8, 0x8E);
}
__asm__ __volatile__("lidt %0": :"m"(idt_pointer));
}
我哪里做错了?
额外的问题:有没有 macro/another 方法自动 link GDT 的第 i 个入口到第 i 个中断处理程序,让我试着更好地解释一下自己:
我想做的是这样的:
for(unsigned int i = 0; i < 256; i++)
{
idt_set_gate(i, (uint32)&interrupt_handler_[i], 0x8, 0x8E);
}
其中 interrupt_handler[i] 将是中断处理程序_[i] 将被 nasm 宏替换
您需要在 NASM 代码中展开宏。宏定义本身不生成任何代码。它需要在 NASM 代码中明确使用。
您可以使用%rep
指令重复扩展具有不同参数的宏。像这样:
extern common_interrupt_handler
%macro error_code_interrupt_handler 1
global interrupt_handler_%1
interrupt_handler_%1:
push dword %1 ; push the interrupt number
jmp common_interrupt_handler ; jump to the common handler
%endmacro
%macro no_error_code_interrupt_handler 1
global interrupt_handler_%1
interrupt_handler_%1:
push dword 0 ; push 0 as error code
push dword %1 ; push the interrupt number
jmp common_interrupt_handler ; jump to the common handler
%endmacro
; Some CPU exceptions have error codes, some don't
%assign intnum 0
%rep 8 - intnum
no_error_code_interrupt_handler intnum
%assign intnum intnum + 1
%endrep
error_code_interrupt_handler 8
no_error_code_interrupt_handler 9
%assign intnum 10
%rep 16 - intnum
error_code_interrupt_handler intnum
%assign intnum intnum + 1
%endrep
no_error_code_interrupt_handler 16
error_code_interrupt_handler 17
no_error_code_interrupt_handler 18
no_error_code_interrupt_handler 19
no_error_code_interrupt_handler 20
%assign intnum 21 ; first (currently) unassigned CPU exception
%rep 32 - intnum
no_error_code_interrupt_handler intnum
%assign intnum intnum + 1
%endrep
%assign intnum 32 ; first user defined interrupt
%rep 256 - intnum
no_error_code_interrupt_handler intnum
%assign intnum intnum + 1
%endrep
; define a table of interrupt handlers for C code to use
global interrupt_handler_table
interrupt_handler_table:
%assign intnum 0
%rep 256
dd interrupt_handler_ %+ intnum
%assign intnum intnum + 1
%endrep
上面的代码创建了一个 table 的所有中断处理程序,您可以像这样在 C 代码中使用它们:
extern uint32 interrupt_handler_table[256];
for(unsigned int i = 0; i < 256; i++)
{
idt_set_gate(i, interrupt_handler_table[i], 0x8, 0x8E);
}
请注意,我已经为那些确实会生成错误代码的 CPU 异常创建了一个 error_code_interrupt_handler
宏。此外,我已经从您的代码中删除了不必要的 CLI 指令。由于您在 IDT 中使用中断门,因此中断启用标志会自动清除。