C 写入绝对地址不更新值

标签 c memory memory-management pagination kernel

我正在尝试为我的 C 内核编写一个基本的页面管理器。代码是这样的:

#define NUM_PAGES 1024
#define PAGE_SIZE 4096
#define NULL 0

#define IMPORTANT_SEGMENT 0xC0900000

struct page {
    void * addr;
    int in_use;
};

struct page CORE_FILE[NUM_PAGES];

void mem_init() {   
    for (int i = 0; i < NUM_PAGES; i++) {
        CORE_FILE[i].addr = (void*)IMPORTANT_SEGMENT+PAGE_SIZE*i;
        CORE_FILE[i].in_use = 0;        
    }
}

void * allocate() {

    for (int i = 0; i < NUM_PAGES; i++) {
        if (!CORE_FILE[i].in_use) {
            CORE_FILE[i].in_use = 1;        
            return CORE_FILE[i].addr;
        }   
    }

    return NULL;
}

int deallocate(void* p) {

    for (int i = 0; i < NUM_PAGES; i++) {
        if (CORE_FILE[i].addr == p && CORE_FILE[i].in_use) {
            CORE_FILE[i].in_use = 0;
            return 0;
        }   
    }
    return -1;
}

CORE_FILE 是一组结构,仅包含一个字段(用于指示页面是否正在使用)和一个地址(我使用从 IMPORTANT_SEGMENT = 0xC0900000 开始增长的连续地址)。

当我调用 allocate() 时,它会返回正确的 void*,例如我将其转换为 char,但是当我写入地址时,它什么也不做。

我已经检查了 GDB 指向的地址并且是正确的地址。 但是当我检查它的内容时,它们还没有更新(仍然是 0)。

void kmain(void) {
    mem_init();
    int * addr = (int*)allocate();
    *addr = 5;
}

我给 qemu 4 GB 的 RAM 执行:

qemu-system-i386 -m 4G -kernel kernel -gdb tcp::5022

也许我正在写入不存在的内存,或者我可能正在覆盖之后的地址内容。我不知道。

任何想法将不胜感激。

提前谢谢你。

[编辑] 这是我使用的引导加载程序:

bits 32
section .text
        ;multiboot spec
        align 4
        dd 0x1BADB002              ;magic
        dd 0x00                    ;flags
        dd - (0x1BADB002 + 0x00)   ;checksum. m+f+c should be zero

global start
global keyboard_handler
global read_port
global write_port
global load_idt

extern kmain        ;this is defined in the c file
extern keyboard_handler_main

read_port:
    mov edx, [esp + 4]
            ;al is the lower 8 bits of eax
    in al, dx   ;dx is the lower 16 bits of edx
    ret

write_port:
    mov   edx, [esp + 4]    
    mov   al, [esp + 4 + 4]  
    out   dx, al  
    ret

load_idt:
    mov edx, [esp + 4]
    lidt [edx]
    sti                 ;turn on interrupts
    ret

keyboard_handler:                 
    call    keyboard_handler_main
    iretd

start:
    cli                 ;block interrupts
    mov esp, stack_space
    call kmain
    hlt                 ;halt the CPU

section .bss
resb 8192; 8KB for stack
stack_space:

我的链接.ld

OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
SECTIONS
 {
   . = 0x100000;
   .text : { *(.text) }
   . = 0x200000;
   .data : { *(.data) }
   . = 0x300000;
   .bss  : { *(.bss)  }
 }

Edit2:我用这个编译

nasm -f elf32 kernel.asm -o kasm.o
gcc -g -fno-stack-protector -fno-builtin -m32 -c memory.c -o memory.o
gcc -g -fno-stack-protector -fno-builtin -m32 -c kernel.c -o kc.o
ld -m elf_i386 -T link.ld -o kernel kasm.o memory.o kc.o

最佳答案

问题在于保护模式和实模式,当计算机以 16 位实模式启动时,这使您能够处理 1 MB 的数据。上面的所有内容都不适合读/写。如果我将 IMPORTANT_SEGMENT 更改为 0x300000,它会起作用。

现在我必须创建并加载我的 gdt,启用 a20 行,启用保护模式,设置寄存器并跳转到我的代码。

关于C 写入绝对地址不更新值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56307186/

相关文章:

c++ - 传入 A::operator new() 的大小是否总是等于 sizeof(A)?

c - 如何用C语言为虚拟文件系统创建一个大的二进制文件?

objective-c - 使用 ABAddressBook 进行内存管理

c - 为什么 Valgrind 在 calloc 语句上显示内存泄漏

c++ - 如何避免堆分配将 Rendercommands 插入到 RenderCommandBuffer?

Java 发布资源

image - 在这个node.js图像模块中,我应该使用哪个? (读取流还是从路径?)

c++ - 是否会共享调用者/被调用者堆栈帧的一部分?

c - 在 printf 函数中显示整数

C 检查用户输入错误