diff mbox

Load ELF64 binaries correctly

Message ID 54BFD7A5.5080603@freebsd.org
State Superseded
Headers show

Commit Message

Nathan Whitehorn Jan. 21, 2015, 4:45 p.m. UTC
The attached patch fixes the big-endian ELF64 loader in skiboot to 
handle the fact that the ELF entry point is specified to point to a 
function descriptor describing the entry point rather than the entry 
point itself. (I haven't set it up to load the TOC base pointer though) 
This is required to load the FreeBSD kernel as a skiboot payload. The 
patch does not touch the little-endian loader since I'm not sure if the 
ELFv2 spec still has function descriptors or not.
-Nathan

Comments

Benjamin Herrenschmidt Jan. 22, 2015, 5:02 p.m. UTC | #1
On Wed, 2015-01-21 at 08:45 -0800, Nathan Whitehorn wrote:
> The attached patch fixes the big-endian ELF64 loader in skiboot to 
> handle the fact that the ELF entry point is specified to point to a 
> function descriptor describing the entry point rather than the entry 
> point itself. (I haven't set it up to load the TOC base pointer though) 
> This is required to load the FreeBSD kernel as a skiboot payload. The 
> patch does not touch the little-endian loader since I'm not sure if the 
> ELFv2 spec still has function descriptors or not.

An additional problem is that the Linux 64-bit BE kernel vmlinux doesn't
have a correct function descriptor as an entry point :-( So that patch
breaks loading a raw BE vmlinux... We probably need a quirk to recognize
such an image, possibly via the fact that the value that would be in the
function descriptor cannot possibly be a valid entry point as part of
the image.

As for LE, there are no descriptors.

Cheers,
Ben.

> -Nathan
> _______________________________________________
> Skiboot mailing list
> Skiboot@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/skiboot
Nathan Whitehorn Jan. 23, 2015, 9:32 p.m. UTC | #2
On 01/22/15 09:02, Benjamin Herrenschmidt wrote:
> On Wed, 2015-01-21 at 08:45 -0800, Nathan Whitehorn wrote:
>> The attached patch fixes the big-endian ELF64 loader in skiboot to
>> handle the fact that the ELF entry point is specified to point to a
>> function descriptor describing the entry point rather than the entry
>> point itself. (I haven't set it up to load the TOC base pointer though)
>> This is required to load the FreeBSD kernel as a skiboot payload. The
>> patch does not touch the little-endian loader since I'm not sure if the
>> ELFv2 spec still has function descriptors or not.
> An additional problem is that the Linux 64-bit BE kernel vmlinux doesn't
> have a correct function descriptor as an entry point :-( So that patch
> breaks loading a raw BE vmlinux... We probably need a quirk to recognize
> such an image, possibly via the fact that the value that would be in the
> function descriptor cannot possibly be a valid entry point as part of
> the image.

That's unfortunate. Seeing if the descriptor points into an ELF segment 
marked executable or not shouldn't be that bad, though. I can get coded 
up soon. An alternative would be to change the FreeBSD kernel's entry 
point so that it behaves like Linux, but I would prefer not to do that 
if possible since it could be an upgrade headache for our users.

> As for LE, there are no descriptors.

OK. The LE ABI seems to have removing all the "weirdness" from ppc64 
that it can, so that's what I suspected might be the case.
-Nathan

>
> Cheers,
> Ben.
>
>> -Nathan
>> _______________________________________________
>> Skiboot mailing list
>> Skiboot@lists.ozlabs.org
>> https://lists.ozlabs.org/listinfo/skiboot
>
diff mbox

Patch

diff --git a/core/init.c b/core/init.c
index 2c7e30c..6b794ec 100644
--- a/core/init.c
+++ b/core/init.c
@@ -143,8 +143,10 @@  static bool try_load_elf64(struct elf_hdr *header)
 		    (ph->p_vaddr + ph->p_memsz) < kh->e_entry)
 			continue;
 
-		/* Get our entry */
-		kernel_entry = kh->e_entry - ph->p_vaddr + ph->p_offset;
+		/* Get our entry: note the function descriptor dereference */
+		kernel_entry = *(uint64_t *)(kh->e_entry - ph->p_vaddr +
+		    ph->p_offset + load_base);
+		kernel_entry = kernel_entry - ph->p_vaddr + ph->p_offset;
 		break;
 	}