Page 1 of 1

Very weird problem(possibly linking)

Posted: Fri Oct 19, 2007 1:31 pm
by earlz
Ok, so I am giving OS deving another shot out of extreme boredom...
so I got GRUB working and such and then I got my kernel working so I could goto _main and such with linker scripts(and flat binary format)

so, now I'm working on GDT...but here is the weird part, I'm not havign trouble loading the GDT or anything...I'm having trouble with memset() for whatever reason, when I call any functions out of my strings.c file (I tried making just a test() function to prove it) it doesn't go to the proper address, it goes to some crazy address like 0x8BD0302E or the like...

Here is my linker script:

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY(start)
phys = 0x00100000;
SECTIONS
{
  .text phys : AT(phys) {
    _code = .;
    *(.text)

    . = ALIGN(4096);
  }
  .data : AT(phys + (_data - _code))
  {
    _data = .;
    *(.data)
    *(.rodata)
    . = ALIGN(4096);
  }
  .bss : AT(phys + (_bss - _code))
  {
    _bss = .;
    *(.bss)
    . = ALIGN(4096);
  }
  _end = .;
}
and my flags..

Code: Select all

_CFLAGS= -pipe -nostartfiles -ffreestanding -nostdlib -nostdinc -s -I./include -march=i486 -DDEBUG -DNDEBUG -Wall
_LFLAGS=-s -nostartfiles -nostdlb -Tlink.ld

I can not seem to find any problems...
I am using a i586-elf set of ld and gcc btw(cross-compiler)

edit:
Ok, to help people maybe find a problem, here is my code and disassembly...

Code: Select all

C:
void InstallGdt(){
	unsigned int gdt_size=(sizeof(struct _gdt_entry_bits)*(GDT_LIMIT));
	test(20);
   // _memset(&Gdt,0,gdt_size);
	HALT; //a define for cli hlt --it does NOT get here, it triple faults before it...
    GdtPtr=Gdt;
    gdt_SetBasicCode(2);
    gdt_SetBasicData(1);
    //0x10 is code, 0x08 is data...I like to be different that way...
    gdt_CurrentCS=2;
    gp.limit = (sizeof(struct _gdt_entry_bits) * GDT_LIMIT) - 1;
    gp.base = (void*)&Gdt;
    flush_segments();
}

ASM:
Disassembly of section .text:

00000000 <_InstallGdt>:
       0:       55                      push   %ebp
       1:       89 e5                   mov    %esp,%ebp
       3:       83 ec 08                sub    $0x8,%esp
       6:       c7 45 fc 18 00 00 00    movl   $0x18,0xfffffffc(%ebp)
       d:       83 ec 0c                sub    $0xc,%esp
      10:       6a 14                   push   $0x14
      12:       e8 00 00 00 00          call   17 <_InstallGdt+0x17>
      17:       83 c4 10                add    $0x10,%esp
      1a:       fa                      cli
      1b:       f4                      hlt
      1c:       c7 05 00 00 00 00 00    movl   $0x0,0x0
      23:       00 00 00
      26:       83 ec 0c                sub    $0xc,%esp
      29:       6a 02                   push   $0x2
      2b:       e8 7d 16 00 00          call   16ad <_gdt_SetBasicCode>
      30:       83 c4 10                add    $0x10,%esp
      33:       83 ec 0c                sub    $0xc,%esp
      36:       6a 01                   push   $0x1
      38:       e8 9f 15 00 00          call   15dc <_gdt_SetBasicData>
      3d:       83 c4 10                add    $0x10,%esp
      40:       66 c7 05 00 00 00 00    movw   $0x2,0x0
      47:       02 00
      49:       66 c7 05 00 00 00 00    movw   $0x17,0x0
      50:       17 00
      52:       c7 05 02 00 00 00 00    movl   $0x0,0x2
      59:       00 00 00
      5c:       e8 00 00 00 00          call   61 <_InstallGdt+0x61>
      61:       c9                      leave
      62:       c3                      ret

Posted: Fri Oct 19, 2007 3:51 pm
by os64dev
Ok, so I am giving OS deving another shot out of extreme boredom...
Gee i really feel like helping you know :( .

Does the code triple fault with memset or also without memset.

Posted: Fri Oct 19, 2007 4:22 pm
by jnc100
Okay, so the call to test(20) is here:
hckr83 wrote:

Code: Select all

12:       e8 00 00 00 00          call   17 <_InstallGdt+0x17>
17:       83 c4 10                add    $0x10,%esp 
e8 is the opcode for call (rel32), which is followed by 0x00000000, which usually means there is a relocation to be made somewhere. If this is your object file you're showing, than that is correct. If its the final binary, then hmm...
The relocation table (use readelf -r main.o) should show a relocation at offset 0x13. On i386 ELF objects, for a disp32 argument, it should be of type R_386_PC32, with an addend of -4 (0xfffffffc), and a symbol name of 'test'. If that's true, and readelf -s on strings.o shows the symbol test has an appropriate offset, then there is indeed a problem with your linking/linker somewhere.

Regards,
John.

EDIT: Why, why, why are you stripping all the symbols from your object files?! It surely won't resolve any relocations then...

Posted: Fri Oct 19, 2007 4:44 pm
by earlz
Well, I fixed the stripping thing to where it doesn't do that now, but I still have the problem...

ok, my code relocates to make call 0x00000010 (e8 10 00 00 00)
also, an exerpt of my linker map

Code: Select all

Linker script and memory map

                0x00100000                phys = 0x100000

.text           0x00100000     0x2000 load address 0x00100000
                0x00100000                _code = .
 *(.text)
 .text          0x00100000       0x46 asm.o
                0x00100030                _flush_segments
                0x00100000                start
 *fill*         0x00100046        0x2 00
 .text          0x00100048       0x10 objs/kernel/kernel.o
                0x00100048                _kmain
 .text          0x00100058       0x60 objs/lib/strings.o
                0x00100058                _test
                0x00100087                _memcpy
                0x0010005d                __memset

Posted: Sun Oct 21, 2007 3:11 am
by jnc100
I forgot to add that i386 gcc uses rel type relocations (I've been playing around with x86_64 for a while now and that uses rela), so the value in the object file after e8 is the extra addend (the 'A' in the elf docs).
I've run a simple test case of i386 gcc producing elf objects, fed to an ld to output binary, and the relocations produced do seem to work. I suggest you make a very simple test case, e.g.
file1.c:

Code: Select all

extern int test(int);

int main()
{
  test(20);
  return 0;
}
file2.c:

Code: Select all

int test(int a)
{
  return a;
} 
Compile the two files separately then link. A hex dump should show that the e8 instruction in main is followed by the offset of the test function, relative to the start of the next instruction. If that's the case, the problem is not down to your linker and such. Maybe try introducing each of your command line arguments one-by-one until it starts/stops working? Oh, and you shouldn't need to strip symbols in the ld line either (I was referring to the gcc command line earlier) as binary output doesn't define any symbol tables anyway.

Regards,
John.