Problema con linker script

Iniciado por Khronos14, 4 Septiembre 2012, 13:39 PM

0 Miembros y 1 Visitante están viendo este tema.

Khronos14

Hola, estoy desarrollando un Kernel y tengo un problema con los strings. El Kernel bootea desde la disquetera, carga el Stage2 y entra en modo largo, luego se inicia el Kernel en C++.

Hasta ahora, lo estaba desarrollando en Windows, usando Nasm y MinGW, pero me encontré con el problema de las cadenas y lo porté a GNU/Linux.

En Windows, mi linker script es este:

Código (bash) [Seleccionar]

OUTPUT_FORMAT("pe-x86-64")
ENTRY("loader")
SECTIONS
{
    . = 0x100000;
    .text :
    {
        code = .;
        *(.text)
        text_end = .;
    }
    .rodata :
    {
        rodata = text_end;
        *(.rodata)
*(.rdata)
        rodata_end  = .;     
    }   
    .data :
    {
        data = rodata_end;
        *(.data)
        data_end = .;
    }
    .bss : 
    {
        bss = data_end;
        *(.bss)
        bss__end = .;
    }
    end = .;
}


Y compilo todo, con el siguiente bat:


@echo off
set nasm="tools\nasm.exe"
set bochs="C:\Program Files (x86)\Bochs-2.5.1\bochs.exe"
set fat12maker="tools\fat12maker.exe"
set ld="..\MinGW64\bin\x86_64-w64-mingw32-ld.exe"
set cpp="..\MinGW64\bin\x86_64-w64-mingw32-g++.exe"
set objcopy="..\MinGW64\bin\x86_64-w64-mingw32-objcopy.exe"
set cpp_params=-I.\Kernel\ -nostdlib -nostartfiles -nodefaultlibs -masm=intel -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin

mkdir bin\

%nasm% -fbin bootloader\Stage_1.asm -o Stage_1.bin
if NOT %ERRORLEVEL%==0 goto error

%nasm% -fbin bootloader\Stage_2.asm -o Stage_2.bin
if NOT %ERRORLEVEL%==0 goto error

%cpp% %cpp_params% -c Kernel\kernel.cpp -o bin\kernel.o
%cpp% %cpp_params% -c Kernel\Drivers\screen.cpp -o bin\screen.o
%cpp% %cpp_params% -c Kernel\string.cpp -o bin\string.o
%cpp% %cpp_params% -c Kernel\io.cpp -o bin\io.o
%cpp% %cpp_params% -c Kernel\idt.cpp -o bin\idt.o
%nasm% -f win64 Kernel\Stage_3.asm -o bin\Stage_3.o
if NOT %ERRORLEVEL%==0 goto error

%ld% -nostdlib -nodefaultlibs -T linker.ld bin\Stage_3.o bin\kernel.o bin\idt.o bin\screen.o bin\string.o bin\io.o -o Kernel.out
%objcopy% -x -g -X -S -O binary Kernel.out kernel.bin

copy /b Stage_2.bin+kernel.bin Stage_2.bin
if NOT %ERRORLEVEL%==0 goto error

%fat12maker% -b Stage_1.bin -i Stage_2.bin -o Kernel.img
%bochs% -f bochsconf

goto fin

:error
echo Se produjo un error de compilacion
exit

:fin
echo Compilacion satisfactoria
rmdir /S /Q bin\


Se ejecuta bien, pero no se muestran las cadenas que son constantes globales. No puedo hacer algo como esto:

Código (cpp) [Seleccionar]

const char * interrupts_exceptions[] = {
"0 - Division by zero exception",
"1 - Debug exception",
"2 - Non maskable interrupt",
"3 - Breakpoint exception",
"4 - 'Into detected overflow",
"5 - Out of bounds exception",
"6 - Invalid opcode exception",
"7 - No coprocessor exception",
"8 - Double fault",
"9 - Coprocessor segment overrun",
"10 - Bad TSS",
"11 - Segment not present",
"12 - Stack fault",
"13 - General protection fault",
"14 - Page fault",
"15 - Unknown interrupt exception",
"16 - Coprocessor fault",
"17 - Alignment check exception",
"18 - Machine check exception",
"19 - Reserved exception",
"20 - Reserved exception",
"21 - Reserved exception",
"22 - Reserved exception",
"23 - Reserved exception",
"24 - Reserved exception",
"25 - Reserved exception",
"26 - Reserved exception",
"27 - Reserved exception",
"28 - Reserved exception",
"29 - Reserved exception",
"30 - Reserved exception"
"31 - Reserved exception"};

void idt::init_idt()
{
idt_ptr = (idt_ptr_t*)IDT_ADDRESS;
*idt_entries = (idt_entry_t*)IDT_ADDRESS;

clean_gates();
screen::kprintf("Exceptions pointer: 0x%p\n", ::interrupts_exceptions);
screen::kprintf("String: %s\n", ::interrupts_exceptions[0]); //<--------------------------

idt_set_gate(0, (QWORD)isr0, 0x08, 0x8E);
}


Esto es lo que muestra: http://forum.osdev.org/download/file.php?id=2342&mode=view

Estuve buscando información en http://wiki.osdev.org/Main_Page pero no consigo arreglar el problema.

El linker script de linux es este:

Código (bash) [Seleccionar]

OUTPUT_FORMAT(binary)
ENTRY(loader)
SECTIONS
{
    . = 0x100000;
    .text :
    {
        code = .;
        *(.text)
        text_end = .;
    }
    .rodata :
    {
        rodata = text_end;
        *(.rodata)
        rodata_end  = .;     
    }   
    .data :
    {
        data = rodata_end;
        *(.data)
        data_end = .;
    }
    .bss : 
    {
        bss = data_end;
        *(.bss)
        bss__end = .;
    }
    end = .;
}


Y el Makefile:

Código (bash) [Seleccionar]

CPP = g++
CPP_PARAMS = -I./Kernel/ -nostdlib -nostartfiles -nodefaultlibs -masm=intel -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin
OBJECTS = Stage_3.o kernel.o screen.o string.o io.o idt.o
FAT12MAKER = ./tools/fat12maker/fat12maker


all:
nasm -fbin bootloader/Stage_1.asm -o Stage_1.bin
nasm -fbin bootloader/Stage_2.asm -o Stage_2.o

nasm -felf64 Kernel/Stage_3.asm -o Stage_3.o
$(CPP) $(CPP_PARAMS) -c Kernel/kernel.cpp -o kernel.o
$(CPP) $(CPP_PARAMS) -c Kernel/Drivers/screen.cpp -o screen.o
$(CPP) $(CPP_PARAMS) -c Kernel/string.cpp -o string.o
$(CPP) $(CPP_PARAMS) -c Kernel/io.cpp -o io.o
$(CPP) $(CPP_PARAMS) -c Kernel/idt.cpp -o idt.o

ld -nostdlib -nodefaultlibs -T linker-linux.ld $(OBJECTS) -o Kernel.o
cat Stage_2.o Kernel.o > Stage_2.bin
$(FAT12MAKER) -b Stage_1.bin -i Stage_2.bin -o Kernel.img
bochs -f bochsconf-linux

clean:
rm *.o
rm *.bin


Pero en Linux, funciona peor. Sólo funcionan las cadenas que se declaran como variables locales:

Código (cpp) [Seleccionar]

extern "C" void kmain(WORD Foo, WORD Foo2)
{
char saludo[] = "Hello!\n";
screen::clear_screen();
screen::hide_cursor();

screen::kprintf("Adios\n"); //No funciona
screen::kprintf(saludo); //Funciona


Estoy muy perdido, espero que alguien pueda echarme una mano...

Saludos.

Khronos14

Puede que hay puesto demasiada información, tan solo necesito entender como colocar las secciones de un linker script para el linker de GCC, y para el formato ELF.

Si alguien tiene experiencia trabajando con el linker "a pelo" y puede ayudarme, se lo agradecería mucho.

Saludos.

Khronos14

Bueno, conseguí arreglarlo, tras una semana rompiéndome la cabeza lo conseguí. Este es el linker script, usando MinGW:

Código (bash) [Seleccionar]

OUTPUT_FORMAT("pe-x86-64")
ENTRY(loader)
SECTIONS
{
    .text 0x001216 :
{
*(.text)
}
.rdata :
{
*(.rdata)
}
.data :
{
*(.data)
}
.bss :
{
*(.bss)
}
}


ld -nostdlib -nodefaultlibs -T linker.ld bin\Stage_3.o bin\kernel.o bin\idt.o bin\screen.o bin\string.o bin\io.o -o Kernel.out

Usando el comando ld de esa manera, nos generaría un ejecutable que trabajaría según la dirección de memoria 0x001216.

El Stage_2 de mi Kernel lo cargo en 0x001000, a lo que hay que sumarle el código del Stage_2 que luego carga el Kernel en C++. El tamaño del Stage_2 es de 0x216 bytes, por lo que sumándolo a la dirección base, se soluciona el problema.

Una vez linkeado nuestro ejecutable, lo convertimos a binario con objcopy, tal como hago en el bat que puse antes. Ahora tengo que portarlo a GCC para poder compilarlo en Linux, pero debería ser bastante fácil.

Saludos.

sistemx

Damn quisiera entender un kernel, pero solo se C basico y casi nada de Assembly

Khronos14

Cita de: sistemx en  6 Septiembre 2012, 01:12 AM
Damn quisiera entender un kernel, pero solo se C basico y casi nada de Assembly

Sin ensamblador poco puedes hacer, te compras un libro y te pones un hora al dia o así. Debido al número limitado de instrucciones que tiene, se puede aprender bastante rápido, si ya sabes programar.

Después tendrías que aprender buenas prácticas en ensamblador. Por ejemplo, para poner un registro a 0, puedes hacer:

Código (asm) [Seleccionar]

mov rax, 0
xor rax, rax


Las dos operaciones producen el mismo efecto, pero es más rápida la segunda. Otro ejemplo: la multiplicación por potencias de 2^n.

Código (asm) [Seleccionar]

imul ax, 14, 8


Si ya tienes almacenado en el registro ax un 14, es más rápido esto:

Código (asm) [Seleccionar]

shl ax, 3 ; 2^3 = 8


Son buenas prácticas que adquieres con el tiempo.

Saludos.