Page 1 of 1

Offset errors occurred when changing segment base address

Posted: Sat Oct 27, 2012 11:51 am
by babel92
Hi there,

I ran into some really silly problems and cannot find any solution.
First of all, I setup a flat memory model. All the kernel segments have a base address of 0 (But in fact kernel code begin from 0x100000) and everything went well.
But today when I set the code segment descriptor to a base of 0x100000, things began to go mad. Seems that the IDT initializing C function had a wrong offset of my ISRs (For instance, INT 3 handling routine should be 0x68 instead of 0x100068 I used before. By the way, ISRs are written in asm) . I really don't know how to deal with it.

Thanks.

Compiling environment: Linux
ASM compiler: NASM
C compiler: cc
Linker: ld with script

Flags:

Code: Select all

NASMFLAGS=-f elf
CCFLAGS= -ffreestanding -c -m32 -nostdlib
LDFLAGS=-Ttext 0x100000 -shared --oformat binary -Bsymbolic -z defs -m elf_i386 -T ./link.ld
Linking scripts:

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY(boot_start)
phys = 0x00100000;
SECTIONS
{
  .text phys : AT(phys) {
    code = .;
    *(.text)
    *(.rodata)
    . = ALIGN(4096);
  }
  .data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    . = ALIGN(4096);
  }
  .bss : AT(phys + (bss - code))
  {
    bss = .;
    *(.bss)
    . = ALIGN(4096);
  }
  end = .;
}

Re: Offset errors occurred when changing segment base addres

Posted: Sat Oct 27, 2012 2:55 pm
by Brendan
Hi,
babel92 wrote:I ran into some really silly problems and cannot find any solution.
First of all, I setup a flat memory model. All the kernel segments have a base address of 0 (But in fact kernel code begin from 0x100000) and everything went well.
But today when I set the code segment descriptor to a base of 0x100000, things began to go mad. Seems that the IDT initializing C function had a wrong offset of my ISRs (For instance, INT 3 handling routine should be 0x68 instead of 0x100068 I used before. By the way, ISRs are written in asm) . I really don't know how to deal with it.
For most things you're using offsets within the segment (and not actual addresses). If you load your code at 0x00100000 and were using "segment base = 0" and linking to 0x00100000 before; then if you change to "segment base = 0x00100000" you'd have to link it to 0.

For the address of the GDT and the address of the IDT (stored in the little structure that you load with "LGDT" and "LIDT"); the address is a linear address (and not a virtual address) and isn't effected by segmentation. This means that the linker will get them wrong and you need to adjust the virtual address the linker used into a linear address by adding the segment base to them. Of course if the segment base is zero the linker gets it right (because "linear = virtual + 0 = virtual" in that case).

However; segmentation is bad (useless, annoying, slow and deprecated) and it's likely that the best solution is to revert back to "all the kernel segments have a base address of 0". 8)


Cheers,

Brendan

Re: Offset errors occurred when changing segment base addres

Posted: Sat Oct 27, 2012 4:57 pm
by babel92
Brendan wrote:Hi,
babel92 wrote:I ran into some really silly problems and cannot find any solution.
First of all, I setup a flat memory model. All the kernel segments have a base address of 0 (But in fact kernel code begin from 0x100000) and everything went well.
But today when I set the code segment descriptor to a base of 0x100000, things began to go mad. Seems that the IDT initializing C function had a wrong offset of my ISRs (For instance, INT 3 handling routine should be 0x68 instead of 0x100068 I used before. By the way, ISRs are written in asm) . I really don't know how to deal with it.
For most things you're using offsets within the segment (and not actual addresses). If you load your code at 0x00100000 and were using "segment base = 0" and linking to 0x00100000 before; then if you change to "segment base = 0x00100000" you'd have to link it to 0.

For the address of the GDT and the address of the IDT (stored in the little structure that you load with "LGDT" and "LIDT"); the address is a linear address (and not a virtual address) and isn't effected by segmentation. This means that the linker will get them wrong and you need to adjust the virtual address the linker used into a linear address by adding the segment base to them. Of course if the segment base is zero the linker gets it right (because "linear = virtual + 0 = virtual" in that case).

However; segmentation is bad (useless, annoying, slow and deprecated) and it's likely that the best solution is to revert back to "all the kernel segments have a base address of 0". 8)


Cheers,

Brendan
Finally I decide to undo all the changes to my code (A lot of work, unfortunately :evil: ) according to your suggestion, and going to learn about some paging stuff to make it better.
Thanks! :)