ELF-i386 Relocatable Kernel Modules (Extern Issue)

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
BASICFreak
Member
Member
Posts: 284
Joined: Fri Jan 16, 2009 8:34 pm
Location: Louisiana, USA

ELF-i386 Relocatable Kernel Modules (Extern Issue)

Post by BASICFreak »

Ok, this has finally stumped me...

Loading the ELF into memory everything seems to be working fine, but I'm running into a strange issue.

Let's say I have the following in a Module:

Code: Select all

extern void HAL_RegisterDev(DEV_p Device);
......
printf("0x%x(0x%x)\n", (uint32_t) HAL_RegisterDev, (uint32_t) MyDevice);
HAL_RegisterDev(MyDevice);
the output of the printf is "0x10E15D(0x114004)", which is the correct location for the function, but I get a GPF upon calling HAL_RegisterDev, (cs invalid says bochs).

Now to "patch" the issue I can instead use this code:

Code: Select all

void (*HAL_RegisterDev)(DEV_p Device) = (void(*)(DEV_p)) 0;
......
HAL_RegisterDev = (void(*)(DEV_p)) _API_Get_Symbol("HAL_RegisterDev");
......
printf("0x%x(0x%x)\n", (uint32_t) HAL_RegisterDev, (uint32_t) MyDevice);
HAL_RegisterDev(MyDevice);
in which case HAL_RegisterDev is still at location 0x10E15D, but upon calling the function everything runs as it should.

And for completion here is parts of my ELF Loader:

Code: Select all

void _ELF_PREPARE_SECTIONS(void *File)
{
	ELF32_Head_p Head = File;
	for(uint16_t shd = 0; shd < ELF_SHead_Count(Head); shd++) {
		ELF32_SHead_p SHead = ELF_SHead(Head, shd);
		if((SHead->sh_type == SHT_NOBITS) && (SHead->sh_flags & SHF_ALLOC)) {
			void *SectionLoc = calloc_page((SHead->sh_size / 0x1000) + ((SHead->sh_size % 0x1000) ? 1 : 0));
			SHead->sh_offset = (Elf32_Off) (SectionLoc - File);
			SHead->sh_addr = SectionLoc;
		}
	}
}

bool elf_do_reloc(void *File, uint16_t relocSection)
{
	ELF32_Head_p hdr = File;
	ELF32_SHead_p reltab = ELF_SHead(hdr, relocSection);
	ELF32_SHead_p target = ELF_SHead(hdr, reltab->sh_info);
 	//volatile ELF32_Rel_p RelocTable;
	for(uint32_t x = 0; x < (uint32_t)(reltab->sh_size / reltab->sh_entsize); x++) {
		ELF32_Rel_p RelocTable = (ELF32_Rel_p) (((uint32_t) File + (uint32_t)reltab->sh_offset) + (uint32_t) (x * (uint32_t)reltab->sh_entsize));

		int addr = (int)hdr + target->sh_offset;
		int *ref = (int *)(addr + RelocTable->r_offset);
		// Symbol value
		int symval = 0;
		if(ELF32_R_SYM(RelocTable->r_info) != 0) {
			symval = ELF_Get_SymVal(hdr, reltab->sh_link, ELF32_R_SYM(RelocTable->r_info));
			if(symval == 0) return FALSE;
		}
		// Relocate based on type
		switch(ELF32_R_TYPE(RelocTable->r_info)) {
			case R_386_NONE:
				// No relocation
				break;
			case R_386_32:
				// Symbol + Offset
				*ref = DO_386_32(symval, *ref);
				break;
			case R_386_PC32:
				// Symbol + Offset - Section Offset
				*ref = DO_386_PC32(symval, *ref, (int)target);
				break;
			default:
				return FALSE;
		}
	}
	return TRUE;
}

uint32_t Load_ELF(void *File)
{
	ELF32_Head_p Head = File;
	if(!ELF_isSigned(Head))
		return FALSE;
	_ELF_PREPARE_SECTIONS(File);
	if(ELF_isRelocatable(Head)) {
		// Relocatable ELF
		for(uint16_t shd = 0; shd < (uint16_t) ELF_SHead_Count(Head); shd++)
			if(ELF_SHead(Head, shd)->sh_type == SHT_REL)
				if(!elf_do_reloc(File, shd))
					return FALSE;
	} else if(ELF_isExecutable(Head)) {
		// Non-Relocatable ELF
		return FALSE;
	} else
		return FALSE;
	return ELF_Get_Entry(File);
}

static inline int ELF_Get_SymVal(ELF32_Head_p Head, Elf32_Word Section, Elf32_Word offset) {
		ELF32_SHead_p symtab = ELF_SHead(Head, Section);
		int symaddr = (int)Head + symtab->sh_offset;
		ELF32_SymTbl_p symbol = &((ELF32_SymTbl_p)symaddr)[offset];
		if(symbol->st_shndx == SHN_UNDEF) {
			ELF32_SHead_p strtab = ELF_SHead(Head, symtab->sh_link);
			const char *name = (const char *)Head + strtab->sh_offset + symbol->st_name;
			void *target = (void*)_API_Get_Symbol(name);
			if(target)
				return (int)target;
			return 0;
		} else if(symbol->st_shndx == SHN_ABS)
			return (int) symbol->st_value;
		else {
			ELF32_SHead_p target = ELF_SHead(Head, symbol->st_shndx);
			return (int)Head + symbol->st_value + target->sh_offset;
		}
	}

static inline uint32_t ELF_Get_Entry(void *FILE) {
		ELF32_Head_p Head = (ELF32_Head_p) FILE;
		if (Head->e_entry) {
			if(Head->e_entry > FILE)
				return (uint32_t) Head->e_entry;
			else
				return (uint32_t) ((uint32_t)FILE + (uint32_t)ELF_SHead_By_String(Head, ".text")->sh_offset + Head->e_entry);
		} else {
			ELF32_SHead_p SHead;
			if(SHead = ELF_SHead_By_String(Head, ".text.startup"))
				return (uint32_t) (FILE + SHead->sh_offset);
			else if(SHead = ELF_SHead_By_String(Head, ".text"))
				return (uint32_t) (FILE + SHead->sh_offset);
			else
				return NULL;
		}

	}
hubris
Member
Member
Posts: 28
Joined: Sun May 24, 2015 12:38 am
Location: Brisbane, Australia

Re: ELF-i386 Relocatable Kernel Modules (Extern Issue)

Post by hubris »

I went through something very similar I was transitioning from a binary kernel to a PE kernel, cygwin (I know). After reading so many articles I remained very confused however finally after a little help and a lot of realisation I came to understand that I needed to build a PE loader which parsed the PE file, identified the various sections in the file and moved/copied these sections from the file into the correct positions in memory. This point seems to be glossed over in all/many of the articles I read.

I should say because of PE I am not using GRUB to do the loading, I have written my own in spite of the many recommendations not to.

So my questions how are you loading your kernel into memory?
Hellbender
Member
Member
Posts: 63
Joined: Fri May 01, 2015 2:23 am
Libera.chat IRC: Hellbender

Re: ELF-i386 Relocatable Kernel Modules (Extern Issue)

Post by Hellbender »

BASICFreak wrote:

Code: Select all

extern void HAL_RegisterDev(DEV_p Device);
......
printf("0x%x(0x%x)\n", (uint32_t) HAL_RegisterDev, (uint32_t) MyDevice);
HAL_RegisterDev(MyDevice);
the output of the printf is "0x10E15D(0x114004)", which is the correct location for the function, but I get a GPF upon calling HAL_RegisterDev, (cs invalid says bochs).
I don't see how a near call could change the value of CS to cause the GPF..
Are you sure that the call is the cause and not something that happens inside 'HAL_RegisterDev', or something else around the call point (and just happens to work by chance in the modified version)? What does HAL_RegisterDev do?
Have you put a break before the call and checked the call trace instruction by instruction
(asm volatile ("xchg %bx,%bx"); for bochs)?
Hellbender OS at github.
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: ELF-i386 Relocatable Kernel Modules (Extern Issue)

Post by iansjack »

Hellbender wrote: I don't see how a near call could change the value of CS to cause the GPF.
What makes you think that it's a near call?
Hellbender
Member
Member
Posts: 63
Joined: Fri May 01, 2015 2:23 am
Libera.chat IRC: Hellbender

Re: ELF-i386 Relocatable Kernel Modules (Extern Issue)

Post by Hellbender »

iansjack wrote:
Hellbender wrote: I don't see how a near call could change the value of CS to cause the GPF.
What makes you think that it's a near call?
Because there are no far calls in c.
Edit: that is, on x86 protected mode, although I don't know what platform he's using. I just assumed..
Hellbender OS at github.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: ELF-i386 Relocatable Kernel Modules (Extern Issue)

Post by Combuster »

Hellbender wrote:Because there are no far calls in c.
Somebody never tried Borland/Watcom/Turbo C or one of the others that do. :wink:
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
BASICFreak
Member
Member
Posts: 284
Joined: Fri Jan 16, 2009 8:34 pm
Location: Louisiana, USA

Re: ELF-i386 Relocatable Kernel Modules (Extern Issue)

Post by BASICFreak »

Thanks for the replies, I decided to step through the code and have found to be off by 0x1967 when doing a PC32 relocation.

I needed to do this *ref = DO_386_PC32(symval, *ref, (int)ref); vs *ref = DO_386_PC32(symval, *ref, (int)target);

where target was the location of the SecHead (Section found in relhead->sh_info)

while it should have been the location of int *ref.

Just an FYI, the GPF was actually caused by me executing past the 32MB of ram bochs has.
Post Reply