Link error: relocation truncated to fit: R_386_16 against
Posted: Sun Apr 29, 2007 8:43 am
So I ive taken up the challenge of OS design and am attempting to write a small protected mode OS.
So far I have a 'Hello World' Kernel that boots from grub inside a bochs environment.
Now im trying to take control of the GDT by adding in a little protected mode code.The problem is now when I link in my protected mode code I get a linker error:
pmode.o: In function `pmodeinit':
pmode.asm:(.text+0x7): relocation truncated to fit: R_386_16 against `.data'
pmode.asm:(.text+0x2d): relocation truncated to fit: R_386_16 against `.text'
Ive read the other thread regarding relocation truncated, and assume it has somthing to do with 16 vs 32bit but havent the slightest how to fix it.
Code listing follows...
So far I have a 'Hello World' Kernel that boots from grub inside a bochs environment.
Now im trying to take control of the GDT by adding in a little protected mode code.The problem is now when I link in my protected mode code I get a linker error:
pmode.o: In function `pmodeinit':
pmode.asm:(.text+0x7): relocation truncated to fit: R_386_16 against `.data'
pmode.asm:(.text+0x2d): relocation truncated to fit: R_386_16 against `.text'
Ive read the other thread regarding relocation truncated, and assume it has somthing to do with 16 vs 32bit but havent the slightest how to fix it.
Code listing follows...
Code: Select all
/* link.ld */
ENTRY (loader)
SECTIONS
{
. = 0x00100000;
.text :
{
*(.text)
}
.rodata ALIGN (0x1000) :
{
*(.rodata)
}
.data ALIGN (0x1000) :
{
*(.data)
}
.bss :
{
_sbss = .;
*(COMMON)
*(.bss)
_ebss = .;
}
}
Code: Select all
; Loader.asm
global loader ; making entry point visible to linker
extern main ; _main is defined elsewhere
extern pmodeinit
BITS 32
; 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
section .text
align 4
MultiBootHeader:
dd MAGIC
dd FLAGS
dd CHECKSUM
; reserve initial kernel stack space
STACKSIZE equ 0x4000 ; that's 16k.
loader:
mov esp, stack+STACKSIZE ; set up the stack
push eax ; pass Multiboot magic number
push ebx ; pass Multiboot info structure
call pmodeinit
call main ; call kernel proper
hlt ; halt machine should kernel return
section .bss
align 32
stack:
resb STACKSIZE ; reserve 16k stack on a quadword boundary
Code: Select all
;------------------------------------------------------------------------------
; Filename: pmode.asm
; Description: Takes over after grub has thrown us into protected mode and sets
; up a flat 4GB memory space.
; Author: Adam Scarr ([email protected])
;------------------------------------------------------------------------------
BITS 32
section .data
ALIGN 4
GDTPtr: equ $ + 6
GDT:
NullDes: ; GDT[0] = Null Descriptor
dd 0h
dd 0h
;------------------------------------------------------------------------------
; GDT[1] = Code Descriptor
; Limit: FFFFF Base: 0
; Acessed: 0 Read-Write: 1
; Stack: 0 Code: 1
; Desc. Privelage Level: 0 Present: 1
; User Definable: 0 Reserved Bit: 0
; 32 bit: 1 Granularity: 1 (4k)
;
;------------------------------------------------------------------------------
CodeDes:
dw 0FFFFh ; Limit 15-0
dw 00000h ; Base 15-0
db 00h ; Base 23-16
db 10011010b ; Flags
db 11001111b ; Limit 19-16 + Flags
db 00h ; Base 31-24
;------------------------------------------------------------------------------
; GDT[2] = Data Descriptor
; Limit: FFFFF Base: 0
; Acessed: 0 Read-Write: 1
; Stack: 0 Code: 0
; Desc. Privelage Level: 0 Present: 1
; User Definable: 0 Reserved Bit: 0
; 32 bit: 1 Granularity: 1 (4k)
;
;------------------------------------------------------------------------------
DataDes:
dw 0FFFFh ; Limit 15-0
dw 00000h ; Base 15-0
db 00h ; Base 23-16
db 10010010b ; Flags
db 11001111b ; Limit 19-16 + Flags
db 00h ; Base 31-24
GDTSize: equ $ - GDT
section .text
global pmodeinit
pmodeinit:
xor eax,eax ; Clear EAX
pop eax ; Make a pointer to the GDT
xor ebx,ebx
mov bx,GDT
add eax,ebx
mov dword [GDTPtr+2],eax ; And save it in our variable
mov word [GDTPtr],GDTSize ; with the length of the GDT
cli ; Clear interrupts, we don't do
; interrupt support for the
; protected mode
lgdt [GDTPtr] ; Let the CPU know where the GDT is
mov eax,cr0
or eax,1
mov cr0,eax ; And turn protected mode bit on
db 0eah ; Opcode for FAR jump
dw Start32, 0008h ; Address to jump to
; (0008h is the segment selector of
; this codeseg, 0008h is 0001h (entry
; number in the GDT) in bits 15-3
; 32-bit protected mode with our new GDT Descriptor loaded
Start32:
; Initialize all segment registers to 10h (entry #2 in the GDT)
mov ax,[CodeDes] ; entry #1 in GDT
mov cs,ax
mov ax,[DataDes] ; entry #2 in GDT
mov ds,ax ; ds = 10h
mov es,ax ; es = 10h
mov fs,ax ; fs = 10h
mov gs,ax ; gs = 10h
mov ss,ax ; ss = 10h
; Set the top of stack to allow stack operations.
mov esp,8000h ; arbitrary top of stack
Code: Select all
// main.cpp
#include "video.h"
int main(void) {
Video vid;
vid.clear();
vid.write("Hello World!");
}
Code: Select all
// Video.h
#ifndef VIDEO_H
#define VIDEO_H
class Video {
public:
Video();
~Video();
void clear();
void write(char *cp);
void put(char c);
private:
unsigned short *videomem;
unsigned int off;
unsigned int pos;
};
#endif
Code: Select all
// Video.cpp
#include "video.h"
Video::Video() {
pos = 0;
off = 0;
videomem = (unsigned short*)0xb8000;
}
Video::~Video() { }
void Video::clear() {
unsigned int i;
for(i = 0; i < (80*25); i++) {
videomem[i] = (unsigned char) ' ' | 0x700;
}
pos = 0;
off = 0;
}
void Video::write(char *cp) {
char * str = cp, *ch;
for(ch = str; *ch; ch++) {
put(*ch);
}
}
void Video::put(char c) {
if(pos > 80) {
pos = 0;
off += 80;
}
if(off >= (80*25)) {
clear();
}
videomem[off + pos] = (unsigned char) c | 0x700;
pos++;
}