LD linker problems(help pls)

Programming, for all ages and all languages.
Post Reply
brandonhill7
Posts: 4
Joined: Tue Oct 04, 2011 4:15 pm

LD linker problems(help pls)

Post by brandonhill7 »

I've been working on a little learning OS, teaching myself assembly and just recently began linking C++ and assembly files together. In my kernel, All C++ and asm files are built to COFF object files and then linked by LD, which seems to be working improperly. The problem is that in the final binary, a function call doesn't line up. It jumps to halfway through the function and my little learning project OS crashes. This is probably just my mistake but can anybody tell me what it is? Files are below. I can post IDA views or hex views of the object files if that would help, though everything appears as it should. Thanks.

build.bat

Code: Select all

nasm -f coff -o boilerplate.o boilerplate.asm
gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -ffreestanding -o kernel.o -c kernel.cpp
gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -ffreestanding -o video.o -c video.cpp

ld -T link.ld 

pause
boilerplate.asm

Code: Select all

[BITS 32] 

[extern __Z3garv] 

start:
call __Z3garv

ret
kernel.cpp

Code: Select all

#include "video.h"

__attribute__ ((noreturn)) void gar()
{
	unsigned char hey[13] = "Hello World!";
	
	printCString(hey);
}
video.h

Code: Select all

#ifndef VIDEO_H_INCLUDED
#define VIDEO_H_INCLUDED

void printChar(unsigned char cer);

void printCString(unsigned char * cstring);

#endif
video.cpp

Code: Select all

#include "video.h"

int place = 0;

void printChar(unsigned char cer)
{
	unsigned char * vidMem = (unsigned char *) 0xb8000;
	
	vidMem[place] = cer;
	vidMem[place + 1] = 0x1B;
	place++;
	place++;
}

void printCString(unsigned char * cstring)
{
	int i = 0;
	while (cstring[i] != 0)
	{
		printChar(cstring[i]);
		i++;
	}

}
link.ld

Code: Select all

INPUT(boilerplate.o kernel.o video.o)
OUTPUT(kernel.bin)
OUTPUT_FORMAT("binary")
SECTIONS {
  	.text 0x1000 :  
	{
		code = .;
		boilerplate.o(.text)
		kernel.o(.text)
		video.o(.text)
	}
	.data :  
	{
		data = .;
		*(.data)
	}
	.bss :  
	{
		bss = .;
		*(.data)
	}
	
end = .;
}
kernel.bin

Code: Select all

seg000:00001000                 call    sub_1090
seg000:00001005                 retn
seg000:00001005 ; ---------------------------------------------------------------------------
seg000:00001006                 dd 0
seg000:0000100A                 dd 0
seg000:0000100E                 dw 0
seg000:00001010
seg000:00001010 ; =============== S U B R O U T I N E =======================================
seg000:00001010
seg000:00001010
seg000:00001010 sub_1090        proc near               ; CODE XREF: seg000:00001000p
seg000:00001010                                         ; DATA XREF: sub_10C0r ...
seg000:00001010
seg000:00001010 var_2C          = dword ptr -2Ch
seg000:00001010 var_19          = byte ptr -19h
seg000:00001010
seg000:00001010                 push    edi
seg000:00001011                 push    esi
seg000:00001012                 sub     esp, 24h
seg000:00001015                 lea     edi, [esp+2Ch+var_19]
seg000:00001019                 mov     esi, 1094h
seg000:0000101E                 mov     ecx, 0Dh
seg000:00001023                 rep movsb
seg000:00001025                 lea     eax, [esp+2Ch+var_19]
seg000:00001029                 mov     [esp+2Ch+var_2C], eax
seg000:0000102C                 call    sub_1104             ; <---------------- Problem jump
seg000:00001031                 add     esp, 24h
seg000:00001034                 pop     esi
seg000:00001035                 pop     edi
seg000:00001036                 retn
seg000:00001036 sub_1090        endp
seg000:00001036
seg000:00001037 ; ---------------------------------------------------------------------------
seg000:00001037                 nop
seg000:00001037 ; ---------------------------------------------------------------------------
seg000:00001038                 dd 0
seg000:0000103C                 dd 0
seg000:00001040
seg000:00001040 ; =============== S U B R O U T I N E =======================================
seg000:00001040
seg000:00001040
seg000:00001040 sub_10C0        proc near               ; CODE XREF: seg000:00001077p
seg000:00001040
seg000:00001040 arg_0           = dword ptr  4
seg000:00001040
seg000:00001040                 mov     eax, large ds:1090h
seg000:00001045                 mov     edx, [esp+arg_0]
seg000:00001049                 mov     [eax+0B8000h], dl
seg000:0000104F                 mov     eax, large ds:1090h
seg000:00001054                 mov     byte ptr [eax+0B8001h], 1Bh
seg000:0000105B                 add     large dword ptr ds:1090h, 2
seg000:00001062                 retn
seg000:00001062 sub_10C0        endp
seg000:00001062
seg000:00001063 ; ---------------------------------------------------------------------------
seg000:00001063                 push    ebx ;<---------------------------Jump should land here
seg000:00001064                 sub     esp, 4
seg000:00001067                 mov     ebx, [esp+0Ch]
seg000:0000106B                 mov     al, [ebx]
seg000:0000106D                 test    al, al
seg000:0000106F                 jz      short sub_1104
seg000:00001071
seg000:00001071 loc_10F1:                               ; CODE XREF: seg000:00001082j
seg000:00001071                 movzx   eax, al
seg000:00001074                 mov     [esp], eax
seg000:00001077                 call    sub_10C0
seg000:0000107C                 mov     al, [ebx+1]
seg000:0000107F                 inc     ebx
seg000:00001080                 test    al, al
seg000:00001082                 jnz     short loc_10F1
seg000:00001084
seg000:00001084 ; =============== S U B R O U T I N E =======================================
seg000:00001084
seg000:00001084
seg000:00001084 sub_1104        proc near               ; CODE XREF: sub_1090+1Cp <-not here
seg000:00001084                                         ; seg000:0000106Fj
seg000:00001084                 add     esp, 4
seg000:00001087                 pop     ebx
seg000:00001088                 retn
seg000:00001088 sub_1104        endp ; sp-analysis failed
seg000:00001088
seg000:00001089 ; ---------------------------------------------------------------------------
seg000:00001089                 nop
seg000:0000108A                 nop
seg000:0000108B                 nop
seg000:0000108B ; ---------------------------------------------------------------------------
seg000:0000108C                 dd 0
seg000:00001090                 dd 0
seg000:00001094 aHelloWorld     db 'Hello World!'
seg000:000010A0                 dd 0
seg000:000010A0 seg000          ends
seg000:000010A0
seg000:000010A0
seg000:000010A0                 end
User avatar
xenos
Member
Member
Posts: 1118
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: LD linker problems(help pls)

Post by xenos »

How do you run your code? Do you have a boot loader that loads your kernel and sets up protected mode? Have you checked that protected mode is set up properly?
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
brandonhill7
Posts: 4
Joined: Tue Oct 04, 2011 4:15 pm

Re: LD linker problems(help pls)

Post by brandonhill7 »

My boot loader sets up 32-bit protected mode and load 2 sectors into memory address 0x1000. Asm is below. I have run multiple builds loaded off the same boot loader and have had no problems. LD should know that the kernel is loaded at offset 0x1000 so I don't think that is the problem.

booltloader.bin

Code: Select all

seg000:7C00 B8 00 00                                mov     ax, 0
seg000:7C03 8E D8                                   mov     ds, ax
seg000:7C05 8E C0                                   mov     es, ax
seg000:7C07 B4 02                                   mov     ah, 2
seg000:7C09 B0 02                                   mov     al, 2
seg000:7C0B B5 00                                   mov     ch, 0
seg000:7C0D B1 02                                   mov     cl, 2
seg000:7C0F B6 00                                   mov     dh, 0
seg000:7C11 B2 80                                   mov     dl, 80h ; 'Ç'
seg000:7C13 B7 10                                   mov     bh, 10h
seg000:7C15 B3 00                                   mov     bl, 0
seg000:7C17 CD 13                                   int     13h             ; DISK - READ SECTORS INTO MEMORY
seg000:7C17                                                                 ; AL = number of sectors to read, CH = track, CL = sector
seg000:7C17                                                                 ; DH = head, DL = drive, ES:BX -> buffer to fill
seg000:7C17                                                                 ; Return: CF set on error, AH = status, AL = number of sectors read
seg000:7C19 FA                                      cli
seg000:7C1A BE 3B 7C                                mov     si, 7C3Bh
seg000:7C1D BF 00 05                                mov     di, 500h
seg000:7C20 B9 18 00                                mov     cx, 18h
seg000:7C23 F3 A4                                   rep movsb
seg000:7C25 0F 01 16 53 7C                          lgdt    fword ptr ds:dword_7C53
seg000:7C2A 0F 20 C0                                mov     eax, cr0
seg000:7C2D 66 0D 01 00 00 00                       or      eax, 1
seg000:7C33 0F 22 C0                                mov     cr0, eax
seg000:7C36 EA 59 7C 08 00                          jmp     far ptr 8:7C59h
seg000:7C36                         ; ---------------------------------------------------------------------------
seg000:7C3B 00 00 00 00                             dd 0
seg000:7C3F 00 00 00 00                             dd 0
seg000:7C43 FF FF 00 00                             dd 0FFFFh
seg000:7C47 00 9A CF 00                             dd 0CF9A00h
seg000:7C4B FF FF 00 00                             dd 0FFFFh
seg000:7C4F 00 92 CF 00                             dd 0CF9200h
seg000:7C53 18 00 00 05             dword_7C53      dd 5000018h             ; DATA XREF: seg000:7C25r
seg000:7C57 00                                      db    0
seg000:7C58 00                                      db    0
seg000:7C59 ; ---------------------------------------------------------------------------
seg000:7C59                 mov     ax, 10h
seg000:7C5D                 mov     ds, ax
seg000:7C5F                 assume ds:nothing
seg000:7C5F                 mov     es, ax
seg000:7C61                 assume es:nothing
seg000:7C61                 mov     ss, ax
seg000:7C63                 assume ss:nothing
seg000:7C63                 mov     esp, 90000h
seg000:7C68                 call    far ptr 8:1000h
seg000:7C6F                 cli
seg000:7C70                 hlt
seg000:7C70 ; ---------------------------------------------------------------------------

**********************************************************************

seg000:7DFE 55                                      db  55h ; U
seg000:7DFF AA                                      db 0AAh ; ¬
seg000:7DFF                         seg000          ends
User avatar
xenos
Member
Member
Posts: 1118
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: LD linker problems(help pls)

Post by xenos »

I had a closer look at your disassembly. The boot loader looks fine at first sight, but the kernel.bin looks indeed a bit weird.

It also seems that your linker script is a bit strange. You include .data twice, but you don't include .bss or .rodata (which is where I would expect something like string constants - but I may be wrong in this case, I'm not an expert in COFF format). I would probably use a linker script which looks like this:

Code: Select all

INPUT(boilerplate.o kernel.o video.o)
OUTPUT(kernel.bin)
OUTPUT_FORMAT("binary")
SECTIONS {
     .text 0x1000 : 
   {
      code = .;
      boilerplate.o(.text)
      kernel.o(.text)
      video.o(.text)
      *(.rodata)
   }
   .data : 
   {
      data = .;
      *(.data)
   }
   .bss : 
   {
      bss = .;
      *(.bss)
   }
   
end = .;
}
Another more general thing I would recommend is single-stepping through your code in Bochs - just to see what's going on. And finally, it is usually a good idea to use a cross compiler / linker which operates on plain ELF files (although it should work with COFF as well, but ELF is more common among OS devers). Using a native toolchain may work (I guess you are using Cygwin or MinGW?), but it can sometimes lead to exactly these problems you are experiencing right now.
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
brandonhill7
Posts: 4
Joined: Tue Oct 04, 2011 4:15 pm

Re: LD linker problems(help pls)

Post by brandonhill7 »

No dice. Tried all sorts of different link scripts and get the same error. I tried MinGW earlier on and ld gave complaints about the binary format, so now I've got DJGPP and I get these errors. Is there any way I can build my own toolchain on windows without porting the code myself? I could use ELF files but my version of gcc produces COFF only. Building my own toolchain would probably fix both problems right?
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: LD linker problems(help pls)

Post by jnc100 »

Our 'officially supported' setup is a cross compiler on Cygwin. See GCC Cross-Compiler. Download Cygwin and install the packages recommended in the wiki then run the commands given.

Regards,
John.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: LD linker problems(help pls)

Post by Solar »

You might then want to continue with Bare Bones and C++ Bare Bones, which are known-good examples of getting ASM and C/C++ linked together and loaded by the GRUB bootloader.
Every good solution is obvious once you've found it.
Post Reply