这就是问题:
当我用C语言链接我的脚本时,使用ld,当我在ld中生成elf32-i386文件作为输出格式,将它作为OUTPUT_FORMAT()放在ld脚本中时,我没有任何错误,但如果我尝试放入最后一个OUTPUT_FORMAT()"二进制"或尝试输出扩展名为.bin的文件,我得到的错误如下:
kernel.o: In function `k_main':
kernel.c:(.text+0xe): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_clear_screen':
kernelutils.c:(.text+0xc): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_clear_screen_front':
kernelutils.c:(.text+0x56): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_printf':
kernelutils.c:(.text+0xa0): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_sleep_3sec':
kernelutils.c:(.text+0x152): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelmalloc.o:kernelmalloc.c:(.text+0xc): more undefined references to `_GLOBAL_OFFSET_TABLE_' follow
Run Code Online (Sandbox Code Playgroud)
这不仅发生在编译特定脚本时,所有尝试使用ld链接的脚本,或gcc,因为这会调用ld,在尝试获取带扩展名为.bin的二进制文件时死掉.
当显示其中一个可执行文件的符号(上面输出中的kernel.o)时,我看到符号_GLOBAL_OFFSET_TABLE_未定义,最可怕的部分,上面错误输出中返回错误的所有函数都删除了它们的符号,这是nm输出:
cristian@mymethodman:~/Desktop/kernel/0.0.3/Archivos$ nm kernel.o
U _GLOBAL_OFFSET_TABLE_
U k_clear_screen
U k_clear_screen_front
00000000 T k_main
U k_malloc
U k_printf
U k_sleep_3sec
00000000 T __x86.get_pc_thunk.bx
Run Code Online (Sandbox Code Playgroud)
我怎么能解决这个问题?我将保留下面的链接器脚本以确保它不是.ld文件的问题,同时具有"获取elf"和"获取二进制"版本.提前致谢!
Ld脚本:
获取二进制文件: …
在编写与 C 代码接口的绑定时,我发现将具有灵活数组成员的结构的大量实例转换为 Ada 时存在问题,例如
struct example {
size_t length;
int body[];
};
Run Code Online (Sandbox Code Playgroud)
有人告诉我,Ada 可以使用可区分的类型来复制类似的行为,但我找不到一种方法来使用该字段length作为判别式,同时保持结构的布局,以便记录可以用于与C代码,类似
type Example (Count : Integer := Length) is record
Length : Unsigned_64;
Body : Integer (1 .. Count);
end record;
Run Code Online (Sandbox Code Playgroud)
有什么方法可以用该数组创建类似的类型吗?我现在一直默认获取该位置的地址并自己声明数组以供使用,有没有更好的方法?提前致谢。
我试图在学习汇编的同时学习内核的工作原理,并且在学习如何成功创建可引导的 x86_64 内核的过程中,我遇到了一个问题:
我试图在“main.c”中成功输出一些带有函数的文本(下面的所有文件)通过使用 VGA 缓冲区0xB8000,与我使用 32 位版本的内核原型相同,但不同的是启动文件不同。
这里的问题是,当我对 32 位版本使用完全相同的功能时,它成功地打印到屏幕上,但是当使用新文件达到长模式(multiboot.S和start.S)时,这不会发生,屏幕会变黑在 qemu 中测试时,几秒钟后它崩溃并显示错误消息:
warning: TCG doesn't support requested feature: CPUID.01H:ECX.vmx [bit 5]
qemu-system-x86_64: Trying to execute code outside RAM or ROM at 0x00000000000a0000
Run Code Online (Sandbox Code Playgroud)
为什么会发生这种情况?VGA 缓冲区不在0xB8000,*.S 文件有问题?提前致谢!
我将在此处粘贴内核文件:
内核由 4 个文件组成:“main.c”、“start.S”、“multiboot.S”和链接描述文件“linker.ld”。
这3个文件被链接和编译没有任何错误,文件如下:这是main.c(你会看到一个“basiccolors.h”,这个文件只是定义了vga颜色代码)
#include "basiccolors.h"
#include <stddef.h>
#include <stdint.h>
volatile uint16_t* vga_buffer = (uint16_t*)0xB8000; /* memory location of the VGA textmode buffer */
/* Columns and rows of the VGA buffer */
const int …Run Code Online (Sandbox Code Playgroud) 要与某个硬件(在本例中为 x86 GDT 的 TSS 条目)接口,需要在内存中使用以下结构:
type UInt32 is mod 2 ** 32;
type UInt16 is mod 2 ** 16;
type UInt8 is mod 2 ** 8;
type TSSEntry is record
Limit : UInt16;
BaseLow16 : UInt16;
BaseMid8 : UInt8;
Flags1 : UInt8;
Flags2 : UInt8;
BaseHigh8 : UInt8;
BaseUpper32 : UInt32;
Reserved : UInt32;
end record;
for TSSEntry use record
Limit at 0 range 0 .. 15;
BaseLow16 at 0 range 16 .. 31;
BaseMid8 at 0 range 32 …Run Code Online (Sandbox Code Playgroud) 我想创建一个函数来选择C中的另一个,也许这个C伪代码可以帮助澄清我想要的东西:
void set_method(const char *method)
{
// Check if the method is serial_port
if (strcmp(method, "serial_port") == 0)
{
// assign the alias "print" to serial_print
// something like defing here a function like this:
// print(const char *print) { serial_print(print); }
print(const char *print) = serial_print(const char *message)
}
else if (strcmp(method, "graphical_tty") == 0)
{
// The same that serial_port case but with graphical_tty_print
}
else
{
// Error
}
}
Run Code Online (Sandbox Code Playgroud)
目标是在满足条件时为函数分配"别名",我该怎么做?
我正在使用一个独立的C实现,用clang编译.
我有一个用C++编写的内核尝试,我想知道将它移植到x86_64 UEFI,但是使用GNU-efi lib的EFI bootloader必须用C语言编写.
如何从C跳转到主内核函数?一直使用extern C使得C++特性的使用变得不可能,也许可以使用一些汇编代码,或者我可以使引导加载程序调用ELF文件作为ELF加载器的主要内核.这个解决方案可行吗?