Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
无法使用变量从C代码写入视频内存_C_Assembly_X86_Osdev_Vga - Fatal编程技术网

无法使用变量从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

所以我一直在尝试写一个基本的内核,我甚至写到了屏幕上

我可以通过汇编很容易地做到这一点,但不能通过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, 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:你最好还是把这个问题作为一个新问题来问。