Patchwork Relocable payloads

login
register
about
Submitter Rudolf Marek
Date 2010-02-25 00:03:58
Message ID <4B85BE6E.1030004@assembler.cz>
Download mbox | patch
Permalink /patch/970/
State New
Headers show

Comments

Rudolf Marek - 2010-02-25 00:03:58
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

I have taken memtest reloc.c and glued it into libpayload. Check attached patch.
It adds -fPIC too.

Then I taken the tint payload and make it dynamic via:

../libpayload/bin/lpgcc -shared -o tint.elf tint.o engine.o io.o utils.o

I added -shared to following rule

$(TARGET).elf: $(OBJS)
    $(CC) -shared -o $@ $(OBJS)

And -fPIC to CFLAGS

I used Qemu to test this. And it does start tint! Then I changed the loading
address with attached simple patch coreboot_change_base.patch and STILL does
work! I think I have more luck than I thought.

(Except the stack, I cheated and created the temp 4K stack, but I think this can
be fixed quite easily)

Questions:

1) Does it work really work? I can't believe it.

2) If yes I think we will need to ask Eric to re-license this for libpayload

3) I think we can use this to make coreboot_ram to run on ANY address :) if
someone manages to add -fPIC to our build system. When the coreboot_ram is
created one need to add -shared too.

Rudolf
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkuFvm4ACgkQ3J9wPJqZRNWrFQCfddjeN0irx6eljQYIBSdYodkf
Rm0An2DlZGK7MG+6vqH+APlVKLHLAwzT
=7Nyh
-----END PGP SIGNATURE-----
Kevin O'Connor - 2010-02-28 15:50:18
On Thu, Feb 25, 2010 at 01:03:58AM +0100, Rudolf Marek wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> Hi,
> 
> I have taken memtest reloc.c and glued it into libpayload. Check attached patch.
> It adds -fPIC too.

Nice!

However, I think there is a simpler way to achieve the same goal.

The "-fPIC" option causes the compiler to place all relocations into
separate pages.  This really helps on multi-process operating systems
where the OS can then share all the code pages between multiple
applications.  When the same program/library is loaded twice it only
needs to duplicate the handful of relocation pages - all the code can
be shared.

On coreboot there isn't any value in placing all the relocations into
separate pages as the code isn't going to be "shared" like it would on
an OS.

In order to relocate, I think one really only needs to get at the
relocation information.  So, "-fPIC" shouldn't be needed - instead,
one should be able to use something like the ld "--emit-relocs" flag
to keep the relocation information.  Once the relocs are available,
the SELF format could store them as an array of offsets in a new
"section".  To relocate one should then be able to just do:

u32 reloc_count = ...;
u32 *relocs = ...;
void *final_code_loc = ...;
u32 relocation_delta = final_code_loc - SELF_header_code_loc;

for (i=0; i<reloc_count; i++)
    *(u32*)(final_code_loc + relocs[i]) += relocation_delta;

The relocations contain a list of all the places in the program that
rely on a fixed address.  Once we have that list, it should be
straight forward to update the program for a new fixed location.

-Kevin

Patch

Index: src/boot/selfboot.c
===================================================================
--- src/boot/selfboot.c	(revision 5134)
+++ src/boot/selfboot.c	(working copy)
@@ -327,6 +327,7 @@ 
 	return ret;
 }
 
+#define RELO 0x2000000
 
 static int build_self_segment_list(
 	struct segment *head,
@@ -355,7 +356,7 @@ 
 					segment->type == PAYLOAD_SEGMENT_CODE ?  "code" : "data",
 					ntohl(segment->compression));
 			new = malloc(sizeof(*new));
-			new->s_dstaddr = ntohl((u32) segment->load_addr);
+			new->s_dstaddr = ntohl((u32) segment->load_addr) + RELO;
 			new->s_memsz = ntohl(segment->mem_len);
 			new->compression = ntohl(segment->compression);
 
@@ -376,13 +377,13 @@ 
 				 ntohl(segment->mem_len));
 			new = malloc(sizeof(*new));
 			new->s_filesz = 0;
-			new->s_dstaddr = ntohl((u32) segment->load_addr);
+			new->s_dstaddr = ntohl((u32) segment->load_addr) + RELO;
 			new->s_memsz = ntohl(segment->mem_len);
 			break;
 
 		case PAYLOAD_SEGMENT_ENTRY:
 			printk_debug("  Entry Point 0x%p\n", (void *) ntohl((u32) segment->load_addr));
-			*entry =  ntohl((u32) segment->load_addr);
+			*entry =  ntohl((u32) segment->load_addr) + RELO;
 			/* Per definition, a payload always has the entry point
 			 * as last segment. Thus, we use the occurence of the
 			 * entry point as break condition for the loop.