#include #include #include #include "stone.h" #if stone_coff || stone_pe #include "coff.h" int stone_load_coff (FILE *file, char *filename) { #define defy(CALL) do { if ((CALL)) { stone_report ("%s", #CALL); return defeat (); } } while (0) int i, j, sec; stone_object obj; FILHDR fh; /* File header */ SYMENT *sym = NULL; /* Symbols list (free) */ SCNHDR *sc = NULL; /* Section headers (free) */ RELOC *rel = NULL; /* Relocations (free) */ int strsz; /* Symbol string list size */ char *str = NULL; /* Symbol strings (free) */ char tmp [9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* Find the correct symbol name for the data */ char *symname (SYMENT *sym) { if (sym->e.e.e_zeroes) { memmove (tmp, sym->e.e_name, 8); return tmp; } else return str + sym->e.e.e_offset; } /* Return whether a symbol is an import */ int isimport (SYMENT *sym) { char *name = symname (sym); if (name [0] == '_' && sym->e_scnum == 0 && sym->e_value == 0 && sym->e_sclass == 2) return 1; else return 0; } /* Return whether a symbol is an export */ int isexport (SYMENT *sym) { char *name = symname (sym); if (name [0] == '_' && (sym->e_scnum > 0 || sym->e_value > 0) && sym->e_sclass == 2) return 1; else return 0; } /* Free everything allocated and return in defeat */ int defeat (void) { if (sym != NULL) free (sym); if (sc != NULL) free (sc); if (rel != NULL) free (rel); if (obj.sym != NULL) free (obj.sym); if (obj.src != NULL) free (obj.src); file = NULL; sym = NULL; sc = NULL; rel = NULL; obj.sym = NULL; obj.src = NULL; return -1; } stone_setup (); memset (&obj, 0, sizeof (obj)); obj.user = 1; if ((obj.src = strdup (filename)) == NULL) return -1; defy (fseek (file, 0, SEEK_SET)); if (fread (&fh, 1, sizeof (fh), file) != sizeof (fh)) return defeat (); if (fh.f_magic != 0x014C) return defeat (); /* Read the symbols */ defy (stone_allot (sym, fh.f_nsyms) == NULL); defy (fseek (file, fh.f_symptr, SEEK_SET)); defy (fread (sym, 1, fh.f_nsyms * SYMESZ, file) != fh.f_nsyms * SYMESZ); /* Read the symbol identifiers */ if (fread (&strsz, 1, sizeof (long), file) != sizeof (long) || strsz > 1024 * 64) strsz = 0, str = NULL; else { defy ((str = malloc (strsz)) == NULL); defy ((signed) fread (str + 4, 1, strsz - 4, file) != strsz - 4); *(int *) &str [0] = strsz; } /* Read section data */ defy (stone_allot (sc, fh.f_nscns) == NULL); defy (fseek (file, fh.f_opthdr + FILHSZ, SEEK_SET)); defy (fread (sc, 1, fh.f_nscns * SCNHSZ, file) != fh.f_nscns * SCNHSZ); /* Scan the section data */ for (sec = 0; sec < fh.f_nscns; sec ++) { int oclen, idx; /* Read the code data */ oclen = obj.len; obj.len += sc [sec].s_size; defy (stone_resize (obj.code, obj.len) == NULL); defy (fseek (file, sc [sec].s_scnptr, SEEK_SET)); defy (fread (obj.code + oclen, 1, sc [sec].s_size, file) != sc [sec].s_size); /* Read the relocations */ if (sc [sec].s_nreloc > 0) { idx = obj.nrel; obj.nrel += sc [sec].s_nreloc; defy (stone_resize (obj.rel, obj.nrel) == NULL); defy (stone_allot (rel, sc [sec].s_nreloc) == NULL); defy (fseek (file, sc [sec].s_relptr, SEEK_SET)); defy (fread (rel, 1, sc [sec].s_nreloc * RELSZ, file) != sc [sec].s_nreloc * RELSZ); /* relocations */ for (i = 0; i < sc [sec].s_nreloc; i ++, idx ++) { obj.rel [idx].off = rel [i].r_vaddr; obj.rel [idx].sym = rel [i].r_symndx; if (rel [i].r_type == RELOC_REL32) obj.rel [idx].type = csr_relative; else if (rel [i].r_type == RELOC_ADDR32) obj.rel [idx].type = csr_absolute; else obj.rel [idx].type = csr_unknown; } /* free data */ free (rel); rel = NULL; } } /* Allocate symbol data */ obj.nsym = fh.f_nsyms; defy (stone_allot (obj.sym, obj.nsym) == NULL); memset (obj.sym, 0, sizeof (*obj.sym) * obj.nsym); /* symbols */ for (i = 0; i < (signed) fh.f_nsyms; i += 1 + sym [i].e_numaux) { char *name = symname (&sym [i]); int c; if (name [0] == '_' && name [1] == '_' && name [2] == '_' && name [3] == '?') { /* ___?@? */ /* ^^^^^^ ^^^^^ ^^^^^^^^ */ for (c = 4; name [c] != '?' && name [c] != '\0'; c ++); if (name [c] == '?') c ++; else c = 0; } else c = 0; defy ((obj.sym [i].name = malloc (strlen (name + c) + 1)) == NULL); strcpy (obj.sym [i].name, name + c); obj.sym [i].obj = -1; obj.sym [i].sym = -1; if (sym [i].e_value > 0 && sym [i].e_scnum == 0 && sym [i].e_type == 0 && sym [i].e_sclass == 2) { /* Global unitialized */ defy (stone_resize (obj.code, obj.len + sym [i].e_value) == NULL); memset (obj.code + obj.len, 1, sym [i].e_value); obj.sym [i].off = obj.len; for (j = 0; j < obj.nrel; j ++) if (obj.rel [j].sym == i) *(int *) &obj.code [obj.rel [j].off] += obj.len; obj.len += sym [i].e_value; } else obj.sym [i].off = sym [i].e_value; if (sym [i].e_scnum < 0) obj.sym [i].type = csst_unknown; else if (isexport (&sym [i])) obj.sym [i].type = csst_export; else if (isimport (&sym [i])) obj.sym [i].type = csst_import; else obj.sym [i].type = csst_unknown; } /* Now fill in the relocation bases (For multiple relocations) */ for (i = 0; i < obj.nrel; i ++) obj.rel [i].base = *(int *) &obj.code [obj.rel [i].off]; for (i = 1; i < stone_nobj; i ++) if (stone_obj [i].user <= 0) break; if (i < stone_nobj) stone_obj [i] = obj; else { defy (stone_resize (stone_obj, stone_nobj + 1) == NULL); stone_obj [stone_nobj ++] = obj; } /* Free the data */ free (sc); free (str); free (sym); return i; #undef defy } #endif /* stone_coff || stone_pe */