c脚本中的asm代码问题(与其他asm脚本链接时)

时间:2017-07-22 21:58:47

标签: c gcc assembly linker ld

我会解释我的问题......
我在c +程序集中编写内核,当我在主c脚本中使用gcc编译一些asm作为编译器时,我遇到了这个问题:
所有看起来都很好,脚本一如既往地编译,没有错误或警告,但是当我尝试构建我的程序版本(我正在构建的内核)有一个链接器问题,指向脚本失败。
安装很简单,就像: 第1步:nasm -f elf32 loader.asm -o kasm.o
第2步:gcc -m32 -c kernel.c -o kc.o
第3步:ld -m elf_i386 -T linker.ld -o kernel kasm.o kc.o
而且你获得的可执行文件可以作为内核在qemu上运行 但是当谈到最后一步(第3步)时,我遇到了这个问题:

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

我把这个过程涉及的3个脚本放在这里:
1:kernel.c,主要内核文件

/*
 *
 * 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);
}

正如你可以看到我怀疑的asm代码导致问题在最后,在第二个asm(...) block

脚本2:链接器,链接加载器和内核

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 = .;
   }
}

脚本3:加载器,在汇编中。

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

老实说,我不认为最后一个没有错,但是使用一种我不喜欢的语言进行独立编码,所以,确保一点也不差。
内核的一些规范可能会有所帮助:
执行错误的部分与分页有关 它适用于“更高的一半”,但我不会干扰任何事情。

0 个答案:

没有答案