From 41afa5684ccf2d4ea6a067733b5449bc15774668 Mon Sep 17 00:00:00 2001
From: Nicolas "Pixel" Noble <pixel@nobis-crew.org>
Date: Wed, 12 Aug 2009 07:22:59 +0200
Subject: [PATCH] Fixing ERL's COMMON section loading.

This is a patch to add minimal support for special and custom sections, such as the COMMON one.
All other sections types will now be rejected and cause the erl loading to fail; which is a good thing since we HAVE to handle the specific case then.

The support of the COMMON section is done by having a very stupid and dummy allocator inside of a static array. This array is located inside of the erl code, and is currently 16KB large. Feel free to enlarge it if necessary.
The COMMON section seems to be actually some kind of weird dynamic section, where you have to allocate symbols on the fly for them. The symbol's value become its alignment then.
---
 ps2sdk/ee/erl/src/erl.c |   81 +++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 72 insertions(+), 9 deletions(-)

diff --git a/ps2sdk/ee/erl/src/erl.c b/ps2sdk/ee/erl/src/erl.c
index 9238e8c..5800e90 100644
--- a/ps2sdk/ee/erl/src/erl.c
+++ b/ps2sdk/ee/erl/src/erl.c
@@ -197,6 +197,23 @@ static char * reloc_types[] = {
 #define R_MIPS_HI16 5
 #define R_MIPS_LO16 6
 
+#define SHN_UNDEF       0               /* Undefined section */
+#define SHN_LORESERVE   0xff00          /* Start of reserved indices */
+#define SHN_LOPROC      0xff00          /* Start of processor-specific */
+#define SHN_SCOMMON     0xff03
+#define SHN_HIPROC      0xff1f          /* End of processor-specific */
+#define SHN_LOOS        0xff20          /* Start of OS-specific */
+#define SHN_HIOS        0xff3f          /* End of OS-specific */
+#define SHN_ABS         0xfff1          /* Associated symbol is absolute */
+#define SHN_COMMON      0xfff2          /* Associated symbol is common */
+#define SHN_XINDEX      0xffff          /* Index is in extra table.  */
+#define SHN_HIRESERVE   0xffff          /* End of reserved indices */
+
+#define COMMON_SIZE     16*1024
+#define COMMON_ALIGN    128
+
+static u8 common_mem[COMMON_SIZE] __attribute__((aligned(COMMON_ALIGN))) = { 0 };
+static u32 common_size = 0;
 
 /* These global names will not be 'exported' to the global space. */
 
@@ -576,6 +593,7 @@ int erl_add_global_symbol(const char * symbol, u32 address) {
 static int read_erl(int elf_handle, u8 * elf_mem, u32 addr, struct erl_record_t ** p_erl_record) {
     struct elf_header_t head;
     struct elf_section_t * sec = 0;
+    struct elf_section_t common;
     struct elf_symbol_t * sym = 0;
     struct elf_reloc_t reloc;
     int i, j, erx_compressed;
@@ -828,16 +846,61 @@ return code
             lseek(elf_handle, sec[i].sh_offset, SEEK_SET);
 	    read(elf_handle, reloc_section, sec[i].sh_size);
         }
-
+        
+        common.sh_name = 0;
+        common.sh_type = NOBITS;
+        common.sh_flags = 7;
+        common.sh_addr = (u32) common_mem;
+        common.sh_offset = 0;
+        common.sh_size = COMMON_SIZE;
+        common.sh_link = 0;
+        common.sh_info = 0;
+        common.sh_addralign = COMMON_ALIGN;
+        common.sh_entsize = COMMON_SIZE;
+        
        // We found one relocation section, let's parse it to relocate.
 	dprintf("   Num: Offset   Type           Symbol\n");
 	for (j = 0; j < (sec[i].sh_size / sec[i].sh_entsize); j++) {
 	    int sym_n;
+            struct elf_section_t * psec = 0;
+            char * sname = 0;
+            int shndx;
 
 	    reloc = *((struct elf_reloc_t *) (reloc_section + j * sec[i].sh_entsize));
 
 	    sym_n = reloc.r_info >> 8;
 	    dprintf("%6i: %08X %-14s %3i: ", j, reloc.r_offset, reloc_types[reloc.r_info & 255], sym_n);
+            shndx = sym[sym_n].st_shndx;
+            if (shndx < SHN_LORESERVE) {
+                psec = sec + sym[sym_n].st_shndx;
+                sname = names + psec->sh_name;
+            } else {
+                u32 base_addr;
+                
+                switch(shndx) {
+                case SHN_SCOMMON:
+                case SHN_COMMON:
+                    if ((erl_find_symbol(strtab_names + sym[sym_n].st_name)))
+                        break;
+                    dprintf("Got a COMMON section; allocating data for it.\n");
+                   // Symbol's value is its alignment...
+                    base_addr = align(common_size, sym[sym_n].st_value);
+                    if ((base_addr + sym[sym_n].st_size) >= COMMON_SIZE) {
+                        dprintf("Not enough space in the common section, please increase COMMON_SIZE; needed a total of %u bytes.\n", base_addr + sym[sym_n].st_size);
+                        free_and_return(-1);
+                    }
+                   // Very ugly and dumb allocation, but based on the size of the typical COMMON sections we encounter, that should do.
+                    common_size = base_addr + sym[sym_n].st_size;
+                    add_symbol(NULL, strtab_names + sym[sym_n].st_name, base_addr + (u32)common_mem);
+                    break;
+                default:
+                    dprintf("Got a spurious (unsupported) section index: %04x\n", sym[sym_n].st_shndx);
+                    free_and_return(-1);
+                    break;
+                }
+                psec = &common;
+                sname = "COM";
+            }
 
 	    switch(sym[sym_n].st_info & 15) {
 	    case NOTYPE:
@@ -855,9 +918,9 @@ return code
 		}
 		break;
 	    case SECTION:
-		rprintf("internal section reloc to section %i (%s)\n", sym[sym_n].st_shndx, names + sec[sym[sym_n].st_shndx].sh_name);
-		dprintf("Relocating at %08X.\n", erl_record->bytes + sec[sym[sym_n].st_shndx].sh_addr);
-		if (apply_reloc(erl_record->bytes + sec[sec[i].sh_info].sh_addr + reloc.r_offset, reloc.r_info & 255, (u32) (erl_record->bytes + sec[sym[sym_n].st_shndx].sh_addr)) < 0) {
+		rprintf("internal section reloc to section %i (%s)\n", sym[sym_n].st_shndx, sname);
+		dprintf("Relocating at %08X.\n", erl_record->bytes + psec->sh_addr);
+		if (apply_reloc(erl_record->bytes + sec[sec[i].sh_info].sh_addr + reloc.r_offset, reloc.r_info & 255, (u32) (erl_record->bytes + psec->sh_addr)) < 0) {
 		    dprintf("Something went wrong in relocation.");
 		    free_and_return(-1);
 		}
@@ -873,8 +936,8 @@ return code
 		    }
 		    add_dependancy(erl_record, s->provider);
 		} else {
-    		    dprintf("Relocating at %08X.\n", erl_record->bytes + sec[sym[sym_n].st_shndx].sh_addr + sym[sym_n].st_value);
-		    if (apply_reloc(erl_record->bytes + sec[sec[i].sh_info].sh_addr + reloc.r_offset, reloc.r_info & 255, (u32) (erl_record->bytes + sec[sym[sym_n].st_shndx].sh_addr + sym[sym_n].st_value)) < 0) {
+    		    dprintf("Relocating at %08X.\n", erl_record->bytes + psec->sh_addr + sym[sym_n].st_value);
+		    if (apply_reloc(erl_record->bytes + sec[sec[i].sh_info].sh_addr + reloc.r_offset, reloc.r_info & 255, (u32) (erl_record->bytes + psec->sh_addr + sym[sym_n].st_value)) < 0) {
 			dprintf("Something went wrong in relocation.");
 			free_and_return(-1);
 		    }
@@ -892,7 +955,7 @@ return code
     dprintf("   Num: Value    Size     Type    Bind      Ndx Name\n");
     for (i = 0; i < sec[symtab].sh_size / sec[symtab].sh_entsize; i++) {
 	if (((sym[i].st_info >> 4) == GLOBAL) || ((sym[i].st_info >> 4) == WEAK)) {
-	    if ((sym[i].st_info & 15) != NOTYPE) {
+	    if (((sym[i].st_info & 15) != NOTYPE) && (sym[i].st_shndx < SHN_LORESERVE)) {
 		dprintf("Export symbol:\n");
 		if (add_symbol(erl_record, strtab_names + sym[i].st_name, ((u32)erl_record->bytes) + sec[sym[i].st_shndx].sh_addr + sym[i].st_value) < 0) {
 		    dprintf("Symbol probably already exists, let's ignore that.\n");
@@ -905,7 +968,7 @@ return code
 	  sym[i].st_value, sym[i].st_size, symbol_types[sym[i].st_info & 15],
 	  binding_types[sym[i].st_info >> 4], sym[i].st_shndx,
 	  sym[i].st_name ? strtab_names + sym[i].st_name : "(null)",
-	  sym[i].st_shndx ? names + sec[sym[i].st_shndx].sh_name : "(null)");
+	  sym[i].st_shndx < SHN_LORESERVE ? (sym[i].st_shndx ? names + sec[sym[i].st_shndx].sh_name : "(null)") : "COM");
     }
 
 #ifdef _EE
@@ -1168,7 +1231,7 @@ int main(int argc, char ** argv) {
 	fname = "host:hello-erl.erl";
     }
 
-    if (!(erl = load_erl_from_file(fname))) {
+    if (!(erl = load_erl_from_file(fname, 1, &fname))) {
 	dprintf("Error while loading erl file.\n");
 	return -1;
     }
-- 
1.6.2

