Subject: libsa/loadfile.c
To: None <tech-kern@netbsd.org>
From: None <nigel@ind.tansu.com.au>
List: tech-kern
Date: 07/13/2001 15:37:51
Background: I am the maintainer of the Booter program for the Mac68k
            port, and I have recently added preliminary ELF support.
            An alpha version now parses and boots an ELF 1.5 kernel
            which Chuck Silvers made for me. Apart from not finding
            the symbol space, it is all working.


	I did this by throwing away the Booter's existing kernel
parsing code, and using calls to libsa's routines: aout_exec() &
elf_exec(). This should have been the easiest way to go, right?
Take working, thoroughly tested code, and use it.

	Well, I had all sorts of problems. One, I think is a bug in
aout_exec() (I have sent a pr, lib/13435). The other two are missing
features in elf_exec() which I would like to discuss here with a
view to enhancing the code.


	Before I list the problems I had, what code calls loadfile?
It it used very much? (in particular with loading a.out binaries)
I only ask because I find it hard to believe that no-one else has
had the same problem that I had with it.


	These were my problems with loadfile.c, revision 1.10:

1) aout_exec() seems to load files non-zero entry point at the wrong
   address. A kernel with a_entry of 0x2e00 loads at address 0x2e00,
   with its entry point at 0x5c00 !

   Looking at the code, aout_exec() inits minp and maxp to a_entry.
   coff_exec() and elf_exec() do the correct thing, initialising them
   to ~0 and 0 respectively.

2) The symbol space marker returned by elf_exec(), marks[MARK_SYM],
   is set to elfp, which is only set if the LOAD_HDR flag is set.

   Shouldn't MARK_SYM should point to the start of the symbol space?
   It does in aout_exec().

3) Similarly, elf_exec() does not count symbols loaded:
   marks[MARK_NSYM] = 1;	/* XXX: Kernel needs >= 0 */


	Now, the last two are obviously not _essential_ for users
who are just executing a binary, but I need some way to locate the
symbol and string tables (so the Booter can modify kernel variables).
I am not proposing a full suite of elf manip. code (like Solaris),
just changing these two broken return values.

	Here are 10 lines of  code that will do the trick:

% diff -u loadfile.c loadfile_patched.c
--- loadfile.c	Mon Jul  9 12:18:19 2001
+++ loadfile_patched.c	Thu Jul 12 10:20:31 2001
@@ -278,6 +278,8 @@
 	size_t sz;
 	int first;
 	int havesyms;
+	int numsyms = 0;
+	paddr_t symp = 0;
 	paddr_t minp = ~0, maxp = 0, pos;
 	paddr_t offset = marks[MARK_START], shpp, elfp;
 
@@ -383,6 +385,12 @@
 				havesyms = 1;
 
 		for (first = 1, i = 0; i < elf->e_shnum; i++) {
+			if (shp[i].sh_type == SHT_SYMTAB) {
+				if ( ! symp )		/* Save address of first sym section */
+					symp = maxp;
+				numsyms += roundup(shp[i].sh_size,
+						sizeof(long));
+			}
 			if (shp[i].sh_type == SHT_SYMTAB ||
 			    shp[i].sh_type == SHT_STRTAB) {
 				if (havesyms && (flags & LOAD_SYM)) {
@@ -431,8 +439,10 @@
 
 	marks[MARK_START] = LOADADDR(minp);
 	marks[MARK_ENTRY] = LOADADDR(elf->e_entry);
-	marks[MARK_NSYM] = 1;	/* XXX: Kernel needs >= 0 */
-	marks[MARK_SYM] = LOADADDR(elfp);
+	marks[MARK_NSYM] = numsyms;
+	if ( ! numsyms )
+		marks[MARK_NSYM] = 1;	/* XXX: Kernel needs >= 0 */
+	marks[MARK_SYM] = LOADADDR(symp);
 	marks[MARK_END] = LOADADDR(maxp);
 	return 0;
 }
%


	Thoughts?

-- 
| Nigel Pearson, nigel@ind.tansu.com.au | "Reality is that which,   |
|   Telstra NW-D, Sydney, Australia.    |  when you stop believing  |
| Office: 9206 3468    Fax:  9212 6329  |  in it, doesn't go away." |
| Mobile: 0408 664435  Home: 9792 6998  | Philip K. Dick - 'Valis.' |