当我向函数添加更多参数时,为什么我的内核会崩溃?
Why does my kernel crash when I add more arguments to a function?
我正在尝试用 C 构建自定义内核,我想在屏幕上放置一个彩色像素。
我已经切换到保护模式,并将VGA模式设置为0x13,所以我用C写了一个函数,在屏幕的右上角放置一个粉红色的像素:
#include <stdint.h>
#define VGA_MODE 0x13
#define VRAM 0xA0000
#define MAX_HEIGHT 200
#define MAX_LENGTH 320
void PutPixel(uint8_t color, uint16_t x)
{
// Return if x greater than 320
if(x > MAX_LENGTH) return;
unsigned char* ptr = (unsigned char*) VRAM;
ptr += x;
*ptr = color;
return;
}
void KERNEL_MAIN()
{
PutPixel(5, 320);
return;
}
此代码 运行 非常好,直到我想将 y 偏移量作为参数添加到我的 PutPixel 函数以便在另一行上绘制像素:
#include <stdint.h>
#define VGA_MODE 0x13
#define VRAM 0xA0000
#define MAX_HEIGHT 200
#define MAX_LENGTH 320
void PutPixel(uint8_t color, uint16_t x, uint16_t y)
{
// Return if x greater than 320
if(x > MAX_LENGTH) return;
unsigned char* ptr = (unsigned char*) VRAM;
ptr += x;
*ptr = color;
return;
}
void KERNEL_MAIN()
{
PutPixel(5, 320, 1);
return;
}
即使我实际上没有使用该参数,当我 运行 VirtualBox 中的代码时,它会立即崩溃并且我在 VirtualBox 调试器中出现以下错误:
dbgf event: DBGFSTOP (hyper)
File: VINF_EM_TRIPLE_FAULT
Line: 0
Function: <NULL>
eax=000a013e ebx=00007eae ecx=00000005 edx=00000005 esi=00000000 edi=0000fff0
eip=00000083 esp=0002ffac ebp=490002ff iopl=0 nv up di pl nz na pe nc
cs=0008 ds=0010 es=0010 fs=0010 gs=0010 ss=0010 eflags=00200002
0008:00000083 f0 53 Illegal opcode
VBoxDbg>
我能得到一些帮助吗?
编辑:我发现堆栈被一个字节弄乱了,所以我
反汇编函数调用,它看起来像这样:
%0000000000007ee7 55 push ebp
%0000000000007ee8 48 dec eax
%0000000000007ee9 89 e5 mov ebp, esp
%0000000000007eeb 48 dec eax
%0000000000007eec 83 ec 10 sub esp, byte 000000010h
%0000000000007eef 89 d0 mov eax, edx
%0000000000007ef1 44 inc esp ;???
%0000000000007ef2 89 c2 mov edx, eax
%0000000000007ef4 88 4d 10 mov byte [ebp+010h], cl
%0000000000007ef7 66 89 45 18 mov word [ebp+018h], ax
%0000000000007efb 89 d0 mov eax, edx
%0000000000007efd 66 89 45 20 mov word [ebp+020h], ax
%0000000000007f01 66 81 7d 18 40 01 cmp word [ebp+018h], word 00140h
%0000000000007f07 77 1c jnbe +01ch (000007f25h)
%0000000000007f09 48 dec eax
%0000000000007f0a c7 45 f8 00 00 0a 00 mov dword [ebp-008h], 0000a0000h
%0000000000007f11 0f b7 45 18 movzx eax, [ebp+018h]
%0000000000007f15 48 dec eax
%0000000000007f16 01 45 f8 add dword [ebp-008h], eax
%0000000000007f19 48 dec eax
%0000000000007f1a 8b 45 f8 mov eax, dword [ebp-008h]
%0000000000007f1d 0f b6 55 10 movzx edx, byte [ebp+010h]
%0000000000007f21 88 10 mov byte [eax], dl
%0000000000007f23 eb 01 jmp +001h (000007f26h)
%0000000000007f25 90 nop
%0000000000007f26 48 dec eax
%0000000000007f27 83 c4 10 add esp, byte 000000010h
%0000000000007f2a 5d pop ebp
%0000000000007f2b c3 retn
当我丢弃 0x7ef1 处的 inc esp
指令时,retn
正确弹出 return 地址,但为什么这条指令一开始就在那里?
我在添加编译器选项时找到了解决方案:
gcc -mno-red-zone
现在可以正常使用了,谢谢!
我正在尝试用 C 构建自定义内核,我想在屏幕上放置一个彩色像素。
我已经切换到保护模式,并将VGA模式设置为0x13,所以我用C写了一个函数,在屏幕的右上角放置一个粉红色的像素:
#include <stdint.h>
#define VGA_MODE 0x13
#define VRAM 0xA0000
#define MAX_HEIGHT 200
#define MAX_LENGTH 320
void PutPixel(uint8_t color, uint16_t x)
{
// Return if x greater than 320
if(x > MAX_LENGTH) return;
unsigned char* ptr = (unsigned char*) VRAM;
ptr += x;
*ptr = color;
return;
}
void KERNEL_MAIN()
{
PutPixel(5, 320);
return;
}
此代码 运行 非常好,直到我想将 y 偏移量作为参数添加到我的 PutPixel 函数以便在另一行上绘制像素:
#include <stdint.h>
#define VGA_MODE 0x13
#define VRAM 0xA0000
#define MAX_HEIGHT 200
#define MAX_LENGTH 320
void PutPixel(uint8_t color, uint16_t x, uint16_t y)
{
// Return if x greater than 320
if(x > MAX_LENGTH) return;
unsigned char* ptr = (unsigned char*) VRAM;
ptr += x;
*ptr = color;
return;
}
void KERNEL_MAIN()
{
PutPixel(5, 320, 1);
return;
}
即使我实际上没有使用该参数,当我 运行 VirtualBox 中的代码时,它会立即崩溃并且我在 VirtualBox 调试器中出现以下错误:
dbgf event: DBGFSTOP (hyper)
File: VINF_EM_TRIPLE_FAULT
Line: 0
Function: <NULL>
eax=000a013e ebx=00007eae ecx=00000005 edx=00000005 esi=00000000 edi=0000fff0
eip=00000083 esp=0002ffac ebp=490002ff iopl=0 nv up di pl nz na pe nc
cs=0008 ds=0010 es=0010 fs=0010 gs=0010 ss=0010 eflags=00200002
0008:00000083 f0 53 Illegal opcode
VBoxDbg>
我能得到一些帮助吗?
编辑:我发现堆栈被一个字节弄乱了,所以我 反汇编函数调用,它看起来像这样:
%0000000000007ee7 55 push ebp
%0000000000007ee8 48 dec eax
%0000000000007ee9 89 e5 mov ebp, esp
%0000000000007eeb 48 dec eax
%0000000000007eec 83 ec 10 sub esp, byte 000000010h
%0000000000007eef 89 d0 mov eax, edx
%0000000000007ef1 44 inc esp ;???
%0000000000007ef2 89 c2 mov edx, eax
%0000000000007ef4 88 4d 10 mov byte [ebp+010h], cl
%0000000000007ef7 66 89 45 18 mov word [ebp+018h], ax
%0000000000007efb 89 d0 mov eax, edx
%0000000000007efd 66 89 45 20 mov word [ebp+020h], ax
%0000000000007f01 66 81 7d 18 40 01 cmp word [ebp+018h], word 00140h
%0000000000007f07 77 1c jnbe +01ch (000007f25h)
%0000000000007f09 48 dec eax
%0000000000007f0a c7 45 f8 00 00 0a 00 mov dword [ebp-008h], 0000a0000h
%0000000000007f11 0f b7 45 18 movzx eax, [ebp+018h]
%0000000000007f15 48 dec eax
%0000000000007f16 01 45 f8 add dword [ebp-008h], eax
%0000000000007f19 48 dec eax
%0000000000007f1a 8b 45 f8 mov eax, dword [ebp-008h]
%0000000000007f1d 0f b6 55 10 movzx edx, byte [ebp+010h]
%0000000000007f21 88 10 mov byte [eax], dl
%0000000000007f23 eb 01 jmp +001h (000007f26h)
%0000000000007f25 90 nop
%0000000000007f26 48 dec eax
%0000000000007f27 83 c4 10 add esp, byte 000000010h
%0000000000007f2a 5d pop ebp
%0000000000007f2b c3 retn
当我丢弃 0x7ef1 处的 inc esp
指令时,retn
正确弹出 return 地址,但为什么这条指令一开始就在那里?
我在添加编译器选项时找到了解决方案:
gcc -mno-red-zone
现在可以正常使用了,谢谢!