Subject: loadfile/ELF change to avoid backward seeks
To: None <tech-kern@netbsd.org>
From: Ben Harris <bjh21@netbsd.org>
List: tech-kern
Date: 07/29/2001 16:59:41
In its current design, at least when loading ARM ELF executables built by
the new toolchain, loadfile() sometimes seeks backwards through the file.
This is bad for gzipped files, which have to rewind to the beginning when
this happens.  The problem occurs because ld lays out the file like this:

<ELF header>
<program headers>
.text		PROGBITS
.data		PROGBITS
.ident		PROGBITS
.shstrtab	STRTAB
<section headers>
.symtab		SYMTAB
.strtab		STRTAB

loadfile, though, loads the section headers, and then all the STRTAB and
SYMTAB sections, which means it has to seek backwards to get at .shstrtab.
There's no need for it to load .shstrtab, though, since this just provides
names for the sections, not for any symbols.

What this patch does is to arrange that before deciding to load a STRTAB
section, loadfile checks if any SYMTAB section references it.  If none
does, it skips the section.  This seems to prevent loadfile having to seek
backwards at all when loading arm26 kernels, which seems good to me.

Could someone responsible for loadfile take a look at this and tell me
what they think?

Index: loadfile.c
===================================================================
RCS file: /cvsroot/syssrc/sys/lib/libsa/loadfile.c,v
retrieving revision 1.13
diff -u -u -r1.13 loadfile.c
--- loadfile.c	2001/07/19 18:55:38	1.13
+++ loadfile.c	2001/07/29 15:50:09
@@ -274,7 +274,7 @@
 {
 	Elf_Shdr *shp;
 	Elf_Off off;
-	int i;
+	int i, j;
 	size_t sz;
 	int first;
 	int havesyms;
@@ -378,11 +378,17 @@
 		 */
 		off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(long));

-		for (havesyms = i = 0; i < elf->e_shnum; i++)
-			if (shp[i].sh_type == SHT_SYMTAB)
-				havesyms = 1;
-
+		havesyms = 0;
 		for (first = 1, i = 0; i < elf->e_shnum; i++) {
+			havesyms = 1;
+			if (shp[i].sh_type == SHT_STRTAB) {
+				havesyms = 0;
+				for (j = 0; j < elf->e_shnum; j++)
+					if (shp[j].sh_type == SHT_SYMTAB &&
+					    shp[j].sh_link == i)
+						havesyms = 1;
+			}
+
 			if (shp[i].sh_type == SHT_SYMTAB ||
 			    shp[i].sh_type == SHT_STRTAB) {
 				if (havesyms && (flags & LOAD_SYM)) {
@@ -400,12 +406,12 @@
 						FREE(shp, sz);
 						return 1;
 					}
+				first = 0;
 				}
 				maxp += roundup(shp[i].sh_size,
 				    sizeof(long));
 				shp[i].sh_offset = off;
 				off += roundup(shp[i].sh_size, sizeof(long));
-				first = 0;
 			}
 		}
 		if (flags & LOAD_SYM) {

-- 
Ben Harris                                                   <bjh21@netbsd.org>
Portmaster, NetBSD/arm26               <URL:http://www.netbsd.org/Ports/arm26/>