无法使用变量从C代码写入视频内存
所以我一直在尝试写一个基本的内核,我甚至写到了屏幕上 我可以通过汇编很容易地做到这一点,但不能通过C。以下是从程序集写入屏幕的代码:无法使用变量从C代码写入视频内存,c,assembly,x86,osdev,vga,C,Assembly,X86,Osdev,Vga,所以我一直在尝试写一个基本的内核,我甚至写到了屏幕上 我可以通过汇编很容易地做到这一点,但不能通过C。以下是从程序集写入屏幕的代码: [bits 32] VIDEO_MEMORY equ 0xb8000 WHITE_ON_BLACK equ 0x10 print_string_pm: pusha mov edx, VIDEO_MEMORY print_string_pm_loop: mov al, [ebx] mov ah, WHITE_ON_BLACK cmp al
[bits 32]
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x10
print_string_pm:
pusha
mov edx, VIDEO_MEMORY
print_string_pm_loop:
mov al, [ebx]
mov ah, WHITE_ON_BLACK
cmp al, 0
je print_string_pm_done
mov [edx], ax
add ebx, 1
add edx, 2
jmp print_string_pm_loop
print_string_pm_done:
popa
ret
C_SOURCES = $(wildcard src/*.c)
HEADERS = $(wildcard headers/*.h)
OBJ = ${C_SOURCES:.c=.o}
all: build run
boot_sect.bin:bootloader/main.asm bootloader/gdt.asm bootloader/print_string_pm.asm bootloader/printf.asm bootloader/switch_to_pm.asm bootloader/readDisk.asm
nasm -i./bootloader/ -f bin bootloader/main.asm -o $@
clean:
rm -f *.bin **/*.o
clean_src:
rm -f src/*.o
run: image
qemu-system-x86_64 $<
%.o: src/%.c ${HEADERS}
gcc -I../headers/ -ffreestanding -c $< -o build/$@
%.o: bootloader/%.asm
nasm $< -f elf64 -o build/$@
kernel.bin: ${OBJ} build/kernel_entry.o
ld -o $@ -T link.ld $^ --oformat binary
image: boot_sect.bin kernel.bin
cat $^ > image
build: clean boot_sect.bin kernel.o kernel_entry.o kernel.bin image
这很好,但是从C代码中尝试:
#define VIDEO_MEMORY 0xb8000
#define WHITE_ON_BLACK 0x0f
void main(void) {
char* video_memory = (char*) VIDEO_MEMORY;
*video_memory = 'H';
*(video_memory + 2) = WHITE_ON_BLACK;
*(video_memory + 3) = 'e';
*(video_memory + 5) = 'l';
*(video_memory + 7) = 'l';
*(video_memory + 9) = 'o';
*(video_memory + 11) = ' ';
*(video_memory + 13) = 'W';
*(video_memory + 15) = 'o';
*(video_memory + 17) = 'r';
*(video_memory + 19) = 'l';
*(video_memory + 21) = 'd';
}
这很有效,但效率不高,当我尝试声明字符串时:
void main(void) {
char* video_memory = (char*) VIDEO_MEMORY;
char* str = "Hello World!";
*video_memory = str[0];
*(video_memory + 2) = WHITE_ON_BLACK;
video_memory += 3;
for (int i = 0; str[i] != '\0'; i++) {
*(video_memory) = str[i];
video_memory += 2;
}
}
它只会给我一些奇怪的东西(比如空格或希腊字母)。
我的生成文件:
[bits 32]
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x10
print_string_pm:
pusha
mov edx, VIDEO_MEMORY
print_string_pm_loop:
mov al, [ebx]
mov ah, WHITE_ON_BLACK
cmp al, 0
je print_string_pm_done
mov [edx], ax
add ebx, 1
add edx, 2
jmp print_string_pm_loop
print_string_pm_done:
popa
ret
C_SOURCES = $(wildcard src/*.c)
HEADERS = $(wildcard headers/*.h)
OBJ = ${C_SOURCES:.c=.o}
all: build run
boot_sect.bin:bootloader/main.asm bootloader/gdt.asm bootloader/print_string_pm.asm bootloader/printf.asm bootloader/switch_to_pm.asm bootloader/readDisk.asm
nasm -i./bootloader/ -f bin bootloader/main.asm -o $@
clean:
rm -f *.bin **/*.o
clean_src:
rm -f src/*.o
run: image
qemu-system-x86_64 $<
%.o: src/%.c ${HEADERS}
gcc -I../headers/ -ffreestanding -c $< -o build/$@
%.o: bootloader/%.asm
nasm $< -f elf64 -o build/$@
kernel.bin: ${OBJ} build/kernel_entry.o
ld -o $@ -T link.ld $^ --oformat binary
image: boot_sect.bin kernel.bin
cat $^ > image
build: clean boot_sect.bin kernel.o kernel_entry.o kernel.bin image
看起来您正在遵循的是,或者至少偶然发现了其内容的副本,因为您的汇编代码片段来自 简单地说,您一个字节接一个字节地写入字符和属性,每次都会推进视频内存偏移量。一个粗略的例子:
const char *s = "Hello world";
char *base = (void *) 0xb8000;
while (*s) {
*base++ = *s++;
*base++ = 0x0f;
}
使用处理光标位置的VGA I/O端口覆盖
引入了许多更高级别的函数,用于在VGA文本模式下写入屏幕,其中许多函数专门用于处理。您的汇编代码似乎将字符写入偶数索引,并将属性
WHITE\u ON\u BLACK
写入每个奇数索引。您的C代码将大多数字符写入奇数索引,而该属性仅写入偶数索引的单个位置。您可能希望使用volatile struct{char C,attrib;}*video_memory=(void*)VGA_BASE
帮助您分类放置内容的位置。如果您不同时写入奇数位置,这些字符的属性字节可能是黑对黑?无论如何,您的convert\u to\u struct
函数已中断,因为您正在通过未初始化的指针进行写入。(我想你的操作系统中没有内存保护!)如果你想知道发生了什么废话,看看编译器生成的asm,以后不要忽略编译器警告!(令人惊讶的是,gcc只警告不要使用未初始化的-Wall
)您可能希望按值返回结构,或者只使用匿名结构对象,如vidmem[1]=(struct foo){H',0xf}代码>。比如,您是否碰巧生成了64位代码,并且只将处理器置于32位模式?您所描述的似乎与此相关:我感觉到奇怪的视频输出正在发生什么,即他们已编译/组装了64位代码,处理器处于32位模式。将解释不寻常的输出,可能是这听起来很熟悉的直接副本…我在64位模式下编译它,因为它不允许我使用32位模式…这是我的编译命令nasm$<-f elf64-o build/$@
。我还在问题中添加了Makefile。@StanciuMihai在对另一个问题的回答中,我举例说明了如何解决这个问题。使用NASM构建,使用-felf32
。使用GCC使用-m32
进行编译,并将选项-melf_i386
添加到链接器选项(LD)中。“我给出的答案中有一部分是“可能是未定义行为的原因”“提到这些选项后:添加所有这些选项后仍然不起作用。下面是运行make
的输出ld:i386:x86-64输入文件'src/kernel.o'的体系结构与i386输出不兼容ld:i386:x86-64输入文件'src/mem.o'的体系结构与i386输出不兼容ld:i386:x86-64输入文件'src/screen.o'的体系结构与i386输出不兼容
@StanciuMihai:你最好还是把这个问题作为一个新问题来问。