kernel.c:(.text+0x2d): 未定义对“memset”的引用
kernel.c:(.text+0x2d): undefined reference to `memset'
我正在编写自定义内核,但在 linking 时出现错误。我已经获取了代码并将其分解,但仍然没有运气。这是我的代码:
kernel.c:
#include <string.h>
// define our structure
typedef struct __attribute__ ((packed)) {
unsigned short di, si, bp, sp, bx, dx, cx, ax;
unsigned short gs, fs, es, ds, eflags;
} regs16_t;
// tell compiler our int32 function is external
extern void int32(unsigned char intnum, regs16_t *regs);
// int32 test
void int32_test()
{
int y;
regs16_t regs;
// switch to 320x200x256 graphics mode
regs.ax = 0x0013;
int32(0x10, ®s);
// full screen with blue color (1)
memset((char *)0xA0000, 1, (320*200));
// draw horizontal line from 100,80 to 100,240 in multiple colors
for(y = 0; y < 200; y++)
memset((char *)0xA0000 + (y*320+80), y, 160);
// wait for key
regs.ax = 0x0000;
int32(0x16, ®s);
// switch to 80x25x16 text mode
regs.ax = 0x0003;
int32(0x10, ®s);
}
kernel.asm:
[bits 32]
global int32, _int32
struc regs16_t
.di resw 1
.si resw 1
.bp resw 1
.sp resw 1
.bx resw 1
.dx resw 1
.cx resw 1
.ax resw 1
.gs resw 1
.fs resw 1
.es resw 1
.ds resw 1
.ef resw 1
endstruc
%define INT32_BASE 0x7C00
%define REBASE(x) (((x) - reloc) + INT32_BASE)
%define GDTENTRY(x) ((x) << 3)
%define CODE32 GDTENTRY(1)
%define DATA32 GDTENTRY(2)
%define CODE16 GDTENTRY(3)
%define DATA16 GDTENTRY(4)
%define STACK16 (INT32_BASE - regs16_t_size)
extern int32_test
global start
section .text
align 4
dd 0x1BADB002
dd 0x00
dd - (0x1BADB002 + 0x00)
int32: use32
_int32:
cli
pusha
mov esi, reloc
mov edi, INT32_BASE
mov ecx, (int32_end - reloc)
cld
rep movsb
jmp INT32_BASE
reloc: use32
mov [REBASE(stack32_ptr)], esp
sidt [REBASE(idt32_ptr)]
sgdt [REBASE(gdt32_ptr)]
lgdt [REBASE(gdt16_ptr)]
lea esi, [esp+0x24]
lodsd
mov [REBASE(ib)], al
mov esi, [esi]
mov edi, STACK16
mov ecx, regs16_t_size
mov esp, edi
rep movsb
jmp word CODE16:REBASE(p_mode16)
p_mode16: use16
mov ax, DATA16
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov eax, cr0
and al, ~0x01
mov cr0, eax
jmp word 0x0000:REBASE(r_mode16)
r_mode16: use16
xor ax, ax
mov ds, ax
mov ss, ax
lidt [REBASE(idt16_ptr)]
mov bx, 0x0870
call resetpic
popa
pop gs
pop fs
pop es
pop ds
sti
db 0xCD
ib: db 0x00
cli
xor sp, sp
mov ss, sp
mov sp, INT32_BASE
pushf
push ds
push es
push fs
push gs
pusha
mov bx, 0x2028
call resetpic
mov eax, cr0
inc eax
mov cr0, eax
jmp dword CODE32:REBASE(p_mode32)
p_mode32: use32
mov ax, DATA32
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
lgdt [REBASE(gdt32_ptr)]
lidt [REBASE(idt32_ptr)]
mov esp, [REBASE(stack32_ptr)]
mov esi, STACK16
lea edi, [esp+0x28]
mov edi, [edi]
mov ecx, regs16_t_size
cld
rep movsb
popa
sti
ret
resetpic:
push ax
mov al, 0x11
out 0x20, al
out 0xA0, al
mov al, bh
out 0x21, al
mov al, bl
out 0xA1, al
mov al, 0x04
out 0x21, al
shr al, 1
out 0xA1, al
shr al, 1
out 0x21, al
out 0xA1, al
pop ax
ret
stack32_ptr:
dd 0x00000000
idt32_ptr:
dw 0x0000
dd 0x00000000
gdt32_ptr:
dw 0x0000
dd 0x00000000
idt16_ptr:
dw 0x03FF
dd 0x00000000
gdt16_base:
.null:
dd 0x00000000
dd 0x00000000
.code32:
dw 0xFFFF
dw 0x0000
db 0x00
db 0x9A
db 0xCF
db 0x00
.data32:
dw 0xFFFF
dw 0x0000
db 0x00
db 0x92
db 0xCF
db 0x00
.code16:
dw 0xFFFF
dw 0x0000
db 0x00
db 0x9A
db 0x0F
db 0x00
.data16:
dw 0xFFFF
dw 0x0000
db 0x00
db 0x92
db 0x0F
db 0x00
gdt16_ptr:
dw gdt16_ptr - gdt16_base - 1
dd gdt16_base
int32_end:
start:
call int32_test
hlt
link.ld:
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
SECTIONS
{
. = 0x100000;
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
}
命令行和输出:
# gcc -fno-stack-protector -m32 -c kernel.c -o kc.o
# nasm -f elf32 kernel.asm -o kasm.o
# ld -m elf_i386 -T link.ld -o kernel kasm.o kc.o
kc.o: In function `int32_test':
kernel.c:(.text+0x2d): undefined reference to `memset'
kernel.c:(.text+0x5c): undefined reference to `memset'
一些背景知识:
我正在为我称为 AI 眼镜的自定义项目开发自定义 OS。我目前正在构建一个引导加载程序,它将显示徽标和一些加载指示器。我认为我的指标会有点像 Ubuntu。无论如何,我需要能够进入 VGA 模式并在屏幕上显示内容,而我的(未来)代码的其余部分可以完全启动它。
我的问题:
我如何将 memset 的库导入我的代码,以便 ld 可以完全 link 我的代码。
大多数库函数,包括 memset
,在内核模块中不可用。
您需要创建自己的实现。它应该像单个 for
循环一样简单。由于您也在编写一些程序集,因此您可能想尝试以这种方式编写它。
这里的问题是 linker 在您提供给 ld 的目标文件中没有找到 memset 函数。 kasm.o 和 kc.o 好像都没有这个功能。事实上,这是标准 C 库的一部分。所以,你需要link标准C库,libc.so或libc.a。如果您不想在内核中使用标准 C 库,则需要提供您自己的 memset
实现
我正在编写自定义内核,但在 linking 时出现错误。我已经获取了代码并将其分解,但仍然没有运气。这是我的代码:
kernel.c:
#include <string.h>
// define our structure
typedef struct __attribute__ ((packed)) {
unsigned short di, si, bp, sp, bx, dx, cx, ax;
unsigned short gs, fs, es, ds, eflags;
} regs16_t;
// tell compiler our int32 function is external
extern void int32(unsigned char intnum, regs16_t *regs);
// int32 test
void int32_test()
{
int y;
regs16_t regs;
// switch to 320x200x256 graphics mode
regs.ax = 0x0013;
int32(0x10, ®s);
// full screen with blue color (1)
memset((char *)0xA0000, 1, (320*200));
// draw horizontal line from 100,80 to 100,240 in multiple colors
for(y = 0; y < 200; y++)
memset((char *)0xA0000 + (y*320+80), y, 160);
// wait for key
regs.ax = 0x0000;
int32(0x16, ®s);
// switch to 80x25x16 text mode
regs.ax = 0x0003;
int32(0x10, ®s);
}
kernel.asm:
[bits 32]
global int32, _int32
struc regs16_t
.di resw 1
.si resw 1
.bp resw 1
.sp resw 1
.bx resw 1
.dx resw 1
.cx resw 1
.ax resw 1
.gs resw 1
.fs resw 1
.es resw 1
.ds resw 1
.ef resw 1
endstruc
%define INT32_BASE 0x7C00
%define REBASE(x) (((x) - reloc) + INT32_BASE)
%define GDTENTRY(x) ((x) << 3)
%define CODE32 GDTENTRY(1)
%define DATA32 GDTENTRY(2)
%define CODE16 GDTENTRY(3)
%define DATA16 GDTENTRY(4)
%define STACK16 (INT32_BASE - regs16_t_size)
extern int32_test
global start
section .text
align 4
dd 0x1BADB002
dd 0x00
dd - (0x1BADB002 + 0x00)
int32: use32
_int32:
cli
pusha
mov esi, reloc
mov edi, INT32_BASE
mov ecx, (int32_end - reloc)
cld
rep movsb
jmp INT32_BASE
reloc: use32
mov [REBASE(stack32_ptr)], esp
sidt [REBASE(idt32_ptr)]
sgdt [REBASE(gdt32_ptr)]
lgdt [REBASE(gdt16_ptr)]
lea esi, [esp+0x24]
lodsd
mov [REBASE(ib)], al
mov esi, [esi]
mov edi, STACK16
mov ecx, regs16_t_size
mov esp, edi
rep movsb
jmp word CODE16:REBASE(p_mode16)
p_mode16: use16
mov ax, DATA16
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov eax, cr0
and al, ~0x01
mov cr0, eax
jmp word 0x0000:REBASE(r_mode16)
r_mode16: use16
xor ax, ax
mov ds, ax
mov ss, ax
lidt [REBASE(idt16_ptr)]
mov bx, 0x0870
call resetpic
popa
pop gs
pop fs
pop es
pop ds
sti
db 0xCD
ib: db 0x00
cli
xor sp, sp
mov ss, sp
mov sp, INT32_BASE
pushf
push ds
push es
push fs
push gs
pusha
mov bx, 0x2028
call resetpic
mov eax, cr0
inc eax
mov cr0, eax
jmp dword CODE32:REBASE(p_mode32)
p_mode32: use32
mov ax, DATA32
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
lgdt [REBASE(gdt32_ptr)]
lidt [REBASE(idt32_ptr)]
mov esp, [REBASE(stack32_ptr)]
mov esi, STACK16
lea edi, [esp+0x28]
mov edi, [edi]
mov ecx, regs16_t_size
cld
rep movsb
popa
sti
ret
resetpic:
push ax
mov al, 0x11
out 0x20, al
out 0xA0, al
mov al, bh
out 0x21, al
mov al, bl
out 0xA1, al
mov al, 0x04
out 0x21, al
shr al, 1
out 0xA1, al
shr al, 1
out 0x21, al
out 0xA1, al
pop ax
ret
stack32_ptr:
dd 0x00000000
idt32_ptr:
dw 0x0000
dd 0x00000000
gdt32_ptr:
dw 0x0000
dd 0x00000000
idt16_ptr:
dw 0x03FF
dd 0x00000000
gdt16_base:
.null:
dd 0x00000000
dd 0x00000000
.code32:
dw 0xFFFF
dw 0x0000
db 0x00
db 0x9A
db 0xCF
db 0x00
.data32:
dw 0xFFFF
dw 0x0000
db 0x00
db 0x92
db 0xCF
db 0x00
.code16:
dw 0xFFFF
dw 0x0000
db 0x00
db 0x9A
db 0x0F
db 0x00
.data16:
dw 0xFFFF
dw 0x0000
db 0x00
db 0x92
db 0x0F
db 0x00
gdt16_ptr:
dw gdt16_ptr - gdt16_base - 1
dd gdt16_base
int32_end:
start:
call int32_test
hlt
link.ld:
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
SECTIONS
{
. = 0x100000;
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
}
命令行和输出:
# gcc -fno-stack-protector -m32 -c kernel.c -o kc.o
# nasm -f elf32 kernel.asm -o kasm.o
# ld -m elf_i386 -T link.ld -o kernel kasm.o kc.o
kc.o: In function `int32_test':
kernel.c:(.text+0x2d): undefined reference to `memset'
kernel.c:(.text+0x5c): undefined reference to `memset'
一些背景知识: 我正在为我称为 AI 眼镜的自定义项目开发自定义 OS。我目前正在构建一个引导加载程序,它将显示徽标和一些加载指示器。我认为我的指标会有点像 Ubuntu。无论如何,我需要能够进入 VGA 模式并在屏幕上显示内容,而我的(未来)代码的其余部分可以完全启动它。
我的问题: 我如何将 memset 的库导入我的代码,以便 ld 可以完全 link 我的代码。
大多数库函数,包括 memset
,在内核模块中不可用。
您需要创建自己的实现。它应该像单个 for
循环一样简单。由于您也在编写一些程序集,因此您可能想尝试以这种方式编写它。
这里的问题是 linker 在您提供给 ld 的目标文件中没有找到 memset 函数。 kasm.o 和 kc.o 好像都没有这个功能。事实上,这是标准 C 库的一部分。所以,你需要link标准C库,libc.so或libc.a。如果您不想在内核中使用标准 C 库,则需要提供您自己的 memset
实现