Sort segments before emitting them
authorH. Peter Anvin <hpa@zytor.com>
Fri, 4 Jan 2008 21:03:20 +0000 (13:03 -0800)
committerH. Peter Anvin <hpa@zytor.com>
Fri, 4 Jan 2008 21:03:20 +0000 (13:03 -0800)
Sort segments in address order, to be nice to the loader.
Furthermore, this paves way for eventually issuing single PHDRs for
adjacent sections.

Makefile
elf.c
segment.c [new file with mode: 0644]
segment.h

index cba4dae..4902b09 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -35,7 +35,7 @@ reloc/reloc.elf: $(RELOC_OBJS) reloc/reloc.ld
 
 reloc.o: reloc.S reloc/reloc.bin 
 
-wraplinux: main.o linux.o reloc.o elf.o
+wraplinux: main.o linux.o reloc.o elf.o segment.o
        $(CC) $(LDFLAGS) -o $@ $^
 
 clean:
diff --git a/elf.c b/elf.c
index 211df31..d1caadd 100644 (file)
--- a/elf.c
+++ b/elf.c
@@ -37,6 +37,8 @@ int output_elf(struct segment *segs, addr_t entry, FILE *out)
        uint32_t name_offset;
        uint32_t shoff;
 
+       segs = sort_segments(segs);
+
        for (s = segs; s; s = s->next) {
                nsections++;
                if (s->name)
diff --git a/segment.c b/segment.c
new file mode 100644 (file)
index 0000000..5a163d1
--- /dev/null
+++ b/segment.c
@@ -0,0 +1,59 @@
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * segment.c
+ *
+ * Sort segments according to base address
+ * Eventually add support here for merging segments
+ */
+
+#include <stdlib.h>
+#include <alloca.h>
+#include "segment.h"
+
+static int comp_seg(const void *a, const void *b)
+{
+       const struct segment * const *ap = a;
+       const struct segment * const *bp = b;
+
+       if ((*ap)->address < (*bp)->address)
+               return -1;
+       else if ((*ap)->address > (*bp)->address)
+               return 1;
+       else
+               return 0;
+}
+
+struct segment *sort_segments(struct segment *list)
+{
+       struct segment **ptrs;
+       int nsegments, i;
+       struct segment *sp, **spp;
+
+       nsegments = 0;
+       for (sp = list; sp; sp = sp->next)
+               nsegments++;
+
+       ptrs = alloca(nsegments * sizeof *ptrs);
+       spp = ptrs;
+       for (sp = list; sp; sp = sp->next)
+               *spp++ = sp;
+
+       qsort(ptrs, nsegments, sizeof *ptrs, comp_seg);
+
+       for (i = 0; i < nsegments-1; i++)
+               ptrs[i]->next = ptrs[i+1];
+       ptrs[i]->next = NULL;
+
+       return ptrs[0];
+}
index 4d1097f..bac5f03 100644 (file)
--- a/segment.h
+++ b/segment.h
@@ -19,6 +19,7 @@
 #ifndef SEGMENT_H
 #define SEGMENT_H
 
+#include <stdio.h>
 #include <inttypes.h>
 
 typedef uint32_t addr_t;
@@ -34,6 +35,7 @@ struct segment {
        const void *data;
 };
 
+struct segment *sort_segments(struct segment *list);
 int output_elf(struct segment *segs, addr_t entry, FILE *out);
 
 #endif /* SEGMENT_H */