i will explain my problem...
I'm coding a kernel in c + assembly, and when I coded some asm in-line in the main c script with gcc as compiler I had this problem:
All looked fine, the script compiled as always, without errors or warnings, but when I tried to build the version of my program (the kernel I was building) had a linker problem, pointing to a script failure.
The installation is simple, it is like:
Step 1: nasm -f elf32 loader.asm -o kasm.o
Step 2: gcc -m32 -c kernel.c -o kc.o
Step 3: ld -m elf_i386 -T linker.ld -o kernel kasm.o kc.o
And you get a executable than can be run at qemu as kernel.
But when it came to the last step (the step 3) I had this problem:
kc.o: In function `enablePaging':
kernel.c:(.text+0x379): undefined reference to `__stack_chk_fail_local'
ld: kernel: hidden symbol `__stack_chk_fail_local' isn't defined
ld: final link failed: Bad value
I put here the 3 scripts involved in this process:
1: kernel.c, the main kernel file
/*
*
* kernel.c - version 0.0.1
* This script is under the license of the distributed package, this license
* can be found in the package itself
* Script coded by Cristian Simón for the CKA Proyect
* ----
* License: GNU GPL v3
* Coder: Cristian Simón
* Proyect: CKA
*
*/
#define BLACK_BGROUND 0X07 /* black background */
#define WHITE_TXT 0x07 /* light gray on black text */
#define GREEN_TXT 0x02 /* light green on black text */
#define RED_TXT 0x04 /* light red on black text*/
#include <stddef.h>
#include <stdint.h>
void k_clear_screen();
void k_sleep_3sec();
unsigned int k_printf(char *message, unsigned int line, float color);
/* k_clear_screen : to clear the entire text screen */
void k_clear_screen()
{
char *vidmem = (char *) 0xC00B8000;
unsigned int i=0;
while(i < (80*25*2))
{
vidmem[i]=' ';
i++;
vidmem[i]=BLACK_BGROUND;
i++;
};
};
/* k_printf : the message and the line # */
unsigned int k_printf(char *message, unsigned int line, float color)
{
char *vidmem = (char *) 0xC00B8000;
unsigned int i=0;
i=(line*80*2);
while(*message!=0)
{
if(*message=='\n') // check for a new line
{
line++;
i=(line*80*2);
*message++;
} else {
vidmem[i]=*message;
*message++;
i++;
vidmem[i]=color;
i++;
};
};
return(1);
}
/* k_sleep_10sec : to make a simple delay of aprox 10 sec */
void k_sleep_3sec()
{
int c = 1, d = 1;
for ( c = 1 ; c <= 20000 ; c++ )
for ( d = 1 ; d <= 20000 ; d++ )
{}
}
extern void loadPageDirectory(unsigned int*);
extern void enablePaging();
/*main function*/
void k_main()
{
k_clear_screen();
k_printf(" Wellcome to", 0, WHITE_TXT);
k_printf(" CKA!", 1, GREEN_TXT);
k_printf("==============>", 2, WHITE_TXT);
k_printf(" CKA stands for C Kernel with Assembly", 3, WHITE_TXT);
k_printf(" Version 0.0.1, => based in the job of Debashis Barman", 4, WHITE_TXT);
k_printf(" Contact => assemblyislaw@gmail.com / blueshell@mail2tor.com", 5, WHITE_TXT);
k_printf(" or in the github repository page", 6, WHITE_TXT);
k_sleep_3sec();
k_clear_screen();
//here start the magic
k_printf(" Starting Checkup", 0, RED_TXT);
//paging setup
k_printf(" [Proc1] Setting up paging", 1, WHITE_TXT);
uint32_t page_directory[1024] __attribute__((aligned(4096)));
//set each entry to not present
int i;
for(i = 0; i < 1024; i++)
{
// This sets the following flags to the pages:
// Supervisor: Only kernel-mode can access them
// Write Enabled: It can be both read from and written to
// Not Present: The page table is not present
page_directory[i] = 0x00000002;
}
uint32_t first_page_table[1024] __attribute__((aligned(4096)));
// holds the physical address where we want to start mapping these pages to.
// in this case, we want to map these pages to the very beginning of memory.
unsigned int w;
//we will fill all 1024 entries in the table, mapping 4 megabytes
for(w = 0; w < 1024; w++)
{
// As the address is page aligned, it will always leave 12 bits zeroed.
// Those bits are used by the attributes ;)
first_page_table[w] = (w * 0x1000) | 3; // attributes: supervisor level, read/write, present.
}
// attributes: supervisor level, read/write, present
page_directory[0] = ((unsigned int)first_page_table) | 3;
//paging asm
asm(".text\n\t"
".globl loadPageDirectory\n\t"
"loadPageDirectory:\n\t"
"push %ebp\n\t"
"mov %esp, %ebp\n\t"
"mov 8(%esp), %eax\n\t"
"mov %eax, %cr3\n\t"
"mov %ebp, %esp\n\t"
"pop %ebp\n\t"
"ret"
);
asm(".text\n\t"
".globl enablePaging\n\t"
"enablePaging:\n\t"
"push %ebp\n\t"
"mov %esp, %ebp\n\t"
"mov %cr0, %eax\n\t"
"or $0x80000000, %eax\n\t"
"mov %eax, %cr0\n\t"
"mov %ebp, %esp\n\t"
"pop %ebp\n\t"
"ret"
);
loadPageDirectory(page_directory);
enablePaging();
k_printf("[Proc1] Paging enabled!", 2, GREEN_TXT);
}
As you can see the asm code that is my suspect of cause the problem is at the end, in the second asm(...) block
Script 2: linker, to link loader and kernel
ENTRY(loader)
OUTPUT_FORMAT(elf32-i386)
SECTIONS {
/* The kernel will live at 3GB + 1MB in the virtual
address space, which will be mapped to 1MB in the
physical address space. */
. = 0xC0100000;
.text : AT(ADDR(.text) - 0xC0000000) {
*(.text)
*(.rodata*)
}
.data ALIGN (0x1000) : AT(ADDR(.data) - 0xC0000000) {
*(.data)
}
.bss : AT(ADDR(.bss) - 0xC0000000) {
_sbss = .;
*(COMMON)
*(.bss)
_ebss = .;
}
}
Script 3: Loader, in assembly.
global _loader ; Make entry point visible to linker.
extern k_main ; _main is defined elsewhere
; setting up the Multiboot header - see GRUB docs for details
MODULEALIGN equ 1<<0 ; align loaded modules on page boundaries
MEMINFO equ 1<<1 ; provide memory map
FLAGS equ MODULEALIGN | MEMINFO ; this is the Multiboot 'flag' field
MAGIC equ 0x1BADB002 ; 'magic number' lets bootloader find the header
CHECKSUM equ -(MAGIC + FLAGS) ; checksum required
; This is the virtual base address of kernel space. It must be used to convert virtual
; addresses into physical addresses until paging is enabled. Note that this is not
; the virtual address where the kernel image itself is loaded -- just the amount that must
; be subtracted from a virtual address to get a physical address.
KERNEL_VIRTUAL_BASE equ 0xC0000000 ; 3GB
KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22) ; Page directory index of kernel's 4MB PTE.
section .data
align 0x1000
BootPageDirectory:
; This page directory entry identity-maps the first 4MB of the 32-bit physical address space.
; All bits are clear except the following:
; bit 7: PS The kernel page is 4MB.
; bit 1: RW The kernel page is read/write.
; bit 0: P The kernel page is present.
; This entry must be here -- otherwise the kernel will crash immediately after paging is
; enabled because it can't fetch the next instruction! It's ok to unmap this page later.
dd 0x00000083
times (KERNEL_PAGE_NUMBER - 1) dd 0 ; Pages before kernel space.
; This page directory entry defines a 4MB page containing the kernel.
dd 0x00000083
times (1024 - KERNEL_PAGE_NUMBER - 1) dd 0 ; Pages after the kernel image.
section .text
align 4
MultiBootHeader:
dd MAGIC
dd FLAGS
dd CHECKSUM
; reserve initial kernel stack space -- that's 16k.
STACKSIZE equ 0x4000
; setting up entry point for linker
loader equ (_loader - 0xC0000000)
global loader
_loader:
; NOTE: Until paging is set up, the code must be position-independent and use physical
; addresses, not virtual ones!
mov ecx, (BootPageDirectory - KERNEL_VIRTUAL_BASE)
mov cr3, ecx ; Load Page Directory Base Register.
mov ecx, cr4
or ecx, 0x00000010 ; Set PSE bit in CR4 to enable 4MB pages.
mov cr4, ecx
mov ecx, cr0
or ecx, 0x80000000 ; Set PG bit in CR0 to enable paging.
mov cr0, ecx
; Start fetching instructions in kernel space.
; Since eip at this point holds the physical address of this command (approximately 0x00100000)
; we need to do a long jump to the correct virtual address of StartInHigherHalf which is
; approximately 0xC0100000.
lea ecx, [StartInHigherHalf]
jmp ecx ; NOTE: Must be absolute jump!
StartInHigherHalf:
; Unmap the identity-mapped first 4MB of physical address space. It should not be needed
; anymore.
mov dword [BootPageDirectory], 0
invlpg [0]
; NOTE: From now on, paging should be enabled. The first 4MB of physical address space is
; mapped starting at KERNEL_VIRTUAL_BASE. Everything is linked to this address, so no more
; position-independent code or funny business with virtual-to-physical address translation
; should be necessary. We now have a higher-half kernel.
mov esp, stack+STACKSIZE ; set up the stack
push eax ; pass Multiboot magic number
; pass Multiboot info structure -- WARNING: This is a physical address and may not be
; in the first 4MB!
push ebx
call k_main ; call kernel proper
hlt ; halt machine should kernel return
section .bss
align 32
stack:
resb STACKSIZE ; reserve 16k stack on a uint64_t boundary
Honestly I dont think the last one have nothing wrong, but is Freestanding coding with a language that I dont domine, so well, ensure is nothing bad at all.
Some specs of the kernel that could be helpfull:
The part that does error is related to paging.
It works in "Higher Half", but I dont thing this disturb anything.
User contributions licensed under CC BY-SA 3.0