Issue
I'm programming my kernel (32 bits x86), and I am cursed with a problem I can't see how to solve.
It's the first time I am confronted with such an issue, usually, I program in user space, so, here it is:
This is my kernel entry function:
void _start(){
const char* welcome = "HEYYY IT'S A MEEEE , MAAARIOOO! ";
init_video();
clear_screen();
video_write((char*) welcome, 0x0E, false);
init_idt();
while(1);
}
And the result:
the thing works.
If I check the section .rodata:
Contents of section .rodata:
2000 30313233 34353637 38394142 43444546 0123456789ABCDEF
2010 08000000 48455959 59204954 27532041 ....HEYYY IT'S A
2020 204d4545 4545202c 204d4141 4152494f MEEEE , MAAARIO
2030 4f4f2120 0000000a 00202000 20202020 OO! ..... .
2040 20002000
You can see that our "welcome" variable has been stored in 0x2014.
But... If I do this:
int stuff(long long s, long long a, long long b);
void _start(){
const char* welcome = "HEYYY IT'S A MEEEE , MAAARIOOO! ";
init_video();
clear_screen();
video_write((char*) welcome, 0x0E, false);
init_idt();
while(1);
}
int stuff (long long s, long long b, long long c) {
return 0;
}
Our Italian plumber disappeared:
Our "welcome" variable is now stored at 0x3014, in the .rodata section:
3000 30313233 34353637 38394142 43444546 0123456789ABCDEF
3010 08000000 48455959 59204954 27532041 ....HEYYY IT'S A
3020 204d4545 4545202c 204d4141 4152494f MEEEE , MAAARIO
3030 4f4f2120 0000000a 00202000 20202020 OO! ..... .
3040 20002000 . .
Now, for the spooky part:
There's nothing at 0x3014, when I run the program. If I run GDB, and print "welcome", I get this:
(gdb) print /x welcome
$1 = 0x3014
(gdb) print welcome
$2 = 0x3014 ""
This happens when I add a function with a certain number of arguments, even without using it. So , if I have to guess (correct me if I'm wrong), either this is a stack issue, or this is a compilation/linking issue?
Is it maybe due to the fact that I'm not using a cross-compiler?
Here's the relevant part of the Makefile for the compilation and linking:
EXEC = SaharaOS
CC = gcc
CFLAGS = -fno-PIC -mno-red-zone -fno-stack-protector -std=c11 -m32 -g -ffreestanding -pedantic -Wall
BOOTLOADER_DIR = ./bootloader
BOOTLOADER = $(BOOTLOADER_DIR)/bootloader.bin
ASM_DIR = ./kernel/asm
KERNEL_ENTRY = $(BOOTLOADER_DIR)/kernel_entry/kernel_entry.o
KERNEL_ENTRY_FILE = $(BOOTLOADER_DIR)/kernel_entry/kernel_entry.asm
KERNEL = ./kernel.bin
KDEBUG = ./symbol-debug-kernel
KERNEL_DIR = ./kernel
KERNEL_SRC_DIR = $(KERNEL_DIR)/src
KERNEL_INC_DIR = $(KERNEL_DIR)/includes
KERNEL_OBJ_DIR = $(KERNEL_DIR)/obj
DRIVERS_DIR = ./drivers
DRIVERS_OBJ_DIR = $(DRIVERS_DIR)/obj
ASM_SRC = $(wildcard $(ASM_DIR)/*.asm)
BOOTLOADER_SRC = $(wildcard $(BOOTLOADER_DIR)/assembly/*.asm)
KERNEL_OBJ = $(wildcard $(KERNEL_OBJ)/*.o)
KERNEL_SRC = $(wildcard $(KERNEL_SRC_DIR)/*.c)
KERNEL_INC = $(wildcard $(KERNEL_INC_DIR)/*.h)
DRIVERS_SRC = $(wildcard $(DRIVERS_DIR)/*/src/*.c)
DRIVERS_INC = $(wildcard $(DRIVERS_DIR)/*/includes/*.h)
OBJ_K = $(KERNEL_SRC:.c=.o)
OBJ_D = $(DRIVERS_SRC:.c=.o)
OBJ_ASM_K = $(ASM_SRC:.asm=.o)
all: run
$(EXEC): assemble
debug: $(EXEC) $(KDEBUG)
qemu-system-i386 -S -gdb tcp::9000 $<
run: $(EXEC)
qemu-system-i386 -d guest_errors $<
disassemble: $(KERNEL)
ndisasm -b 32 $? | cat
assemble: $(BOOTLOADER) $(KERNEL)
cat $^ > $(EXEC)
qemu-img resize $(EXEC) +100K
OBJDUMP: $(KERNEL_ENTRY) $(OBJ_D) $(OBJ_K) $(OBJ_ASM_K)
ld -melf_i386 -o $@ -Ttext 0x1000 $^
#Kernel build and drivers
$(KERNEL): $(KERNEL_ENTRY) $(OBJ_D) $(OBJ_K) $(OBJ_ASM_K)
ld -melf_i386 -o $@ -Ttext 0x1000 $^ --oformat binary
$(KDEBUG): $(KERNEL_ENTRY) $(OBJ_D) $(OBJ_K) $(OBJ_ASM_K)
ld -melf_i386 -o $@ -Ttext 0x1000 $^
%.o: %.c $(KERNEL_INC) $(DRIVERS_INC)
$(CC) $(CFLAGS) -c $< -o $@
%.o: %.asm
nasm -f elf32 -F dwarf -g $< -o $@
#Bootloader build
KERNEL_ENTRY: $(KERNEL_ENTRY)
BOOTLOADER: $(BOOTLOADER)
$(KERNEL_ENTRY):
nasm -f elf32 -F dwarf -g $(KERNEL_ENTRY_FILE) -o $@
$(BOOTLOADER):
nasm $(BOOTLOADER_DIR)/assembly/boot.asm -i $(BOOTLOADER_DIR)/assembly -f bin -o $@
Solution
Although your question doesn't contain a minimal complete verifiable example, I can tell from the Makefile you are using your own custom bootloader and not something like GRUB/Multiboot. Your Makefile also shows that you aren't using something like a linker script or OBJCOPY to trim needed sections from your final kernel binary. This narrows down the types of problems that could be occurring.
A guess would be that the code changes you have made have added a new section to your kernel and has expanded the size of it as well. Since GDB is showing debug information for the string but the memory is zero filled suggests that your bootloader may not have read the entire kernel into memory. The string is likely in the sections that hasn't been fully read. Make sure the number of disk sectors you have read into memory is enough to cover the entire kernel.
Answered By - Michael Petch