diff --git a/tools/elf2hunk.c b/tools/elf2hunk.c index a3dcb09..d24e996 100644 --- a/tools/elf2hunk.c +++ b/tools/elf2hunk.c @@ -1,1134 +1,1134 @@ -/* - Copyright © 1995-2001, The AROS Development Team. All rights reserved. -*/ - -#define PROTOTYPES -#define HAVE_STDARG_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define F_VERBOSE (1 << 0) -#define F_NOCONVERT (1 << 1) - -#if defined(_MSC_VER) - -#include -#include -#define ATTRIBUTE_PACKED -#define ATTRIBUTE_UNUSED -#define lseek _lseek -#define read _read -#define write _write -#define open _open -#define unlink _unlink -#define close _close -#define mkdir(a,b) _mkdir(a) - -#include "msdirent.h" -#include - -#define S_ISDIR(a) (a == 16895) - -#define strcasecmp strcmp - -#else -#include -#include -#define ATTRIBUTE_PACKED __attribute__((packed)) -#define ATTRIBUTE_UNUSED __attribute__((unused)) -#endif - -#if !defined(O_BINARY) -#define O_BINARY 0 -#endif - -#if (defined(__GNUC__))&&defined(WIN32) -#include -#define mkdir(path, mode) mkdir(path) -#elif !defined(_MSC_VER) -#include -typedef uint32_t ULONG; -typedef int BOOL; -#endif -typedef uint8_t UBYTE; -typedef uint16_t UWORD; -typedef uint32_t IPTR; -typedef int32_t SIPTR; -typedef char * STRPTR; - -#if !defined(FALSE)&&!defined(TRUE) -#define FALSE 0 -#define TRUE (!FALSE) -#endif - -/* Memory allocation flags */ -#define MEMF_ANY 0L -#define MEMF_PUBLIC (1L<<0) -#define MEMF_CHIP (1L<<1) -#define MEMF_FAST (1L<<2) -#define MEMF_EXECUTABLE (1L<<4) /* AmigaOS v4 compatible */ -#define MEMF_LOCAL (1L<<8) -#define MEMF_24BITDMA (1L<<9) -#define MEMF_KICK (1L<<10) -#define MEMF_31BIT (1L<<12) /* Low address space (<2GB). Effective only on 64 bit machines. */ -#define MEMF_CLEAR (1L<<16) /* Explicitly clear memory after allocation */ -#define MEMF_LARGEST (1L<<17) -#define MEMF_REVERSE (1L<<18) -#define MEMF_TOTAL (1L<<19) -#define MEMF_HWALIGNED (1L<<20) /* For AllocMem() - align address and size to physical page boundary */ -#define MEMF_SEM_PROTECTED (1L<<20) /* For CreatePool() - add semaphore protection to the pool */ -#define MEMF_NO_EXPUNGE (1L<<31) - -#define HUNKF_ADVISORY (1L<<29) -#define HUNKF_CHIP (1L<<30) -#define HUNKF_FAST (1L<<31) -#define HUNKF_MEMFLAGS (HUNKF_CHIP | HUNKF_FAST) - - -#define HUNK_CODE 1001 -#define HUNK_DATA 1002 -#define HUNK_BSS 1003 -#define HUNK_RELOC32 1004 -#define HUNK_SYMBOL 1008 -#define HUNK_END 1010 -#define HUNK_HEADER 1011 - -#define SHT_PROGBITS 1 -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_RELA 4 -#define SHT_NOBITS 8 -#define SHT_REL 9 -#define SHT_SYMTAB_SHNDX 18 - -#define ET_REL 1 -#define ET_EXEC 2 - -#define EM_386 3 -#define EM_68K 4 -#define EM_PPC 20 -#define EM_ARM 40 -#define EM_X86_64 62 /* AMD x86-64 */ - -#define R_386_NONE 0 -#define R_386_32 1 -#define R_386_PC32 2 - -/* AMD x86-64 relocations. */ -#define R_X86_64_NONE 0 /* No reloc */ -#define R_X86_64_64 1 /* Direct 64 bit */ -#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ -#define R_X86_64_32 10 -#define R_X86_64_32S 11 - -#define R_68k_NONE 0 -#define R_68K_32 1 -#define R_68K_PC32 4 -#define R_68K_PC16 5 - -#define R_PPC_NONE 0 -#define R_PPC_ADDR32 1 -#define R_PPC_ADDR16_LO 4 -#define R_PPC_ADDR16_HA 6 -#define R_PPC_REL24 10 -#define R_PPC_REL32 26 -#define R_PPC_REL16_LO 250 -#define R_PPC_REL16_HA 252 - -#define R_ARM_NONE 0 -#define R_ARM_PC24 1 -#define R_ARM_ABS32 2 -#define R_ARM_CALL 28 -#define R_ARM_JUMP24 29 -#define R_ARM_V4BX 40 -#define R_ARM_PREL31 42 -#define R_ARM_MOVW_ABS_NC 43 -#define R_ARM_MOVT_ABS 44 - -#define STT_NOTYPE 0 -#define STT_OBJECT 1 -#define STT_FUNC 2 -#define STT_SECTION 3 -#define STT_FILE 4 -#define STT_LOPROC 13 -#define STT_HIPROC 15 - -#define SHN_UNDEF 0 -#define SHN_LORESERVE 0xff00 -#define SHN_ABS 0xfff1 -#define SHN_COMMON 0xfff2 -#define SHN_XINDEX 0xffff -#define SHN_HIRESERVE 0xffff - -#define SHF_WRITE (1 << 0) -#define SHF_ALLOC (1 << 1) -#define SHF_EXECINSTR (1 << 2) - -#define ELF_ST_TYPE(i) ((i) & 0x0F) - -#define EI_VERSION 6 -#define EV_CURRENT 1 - -#define EI_DATA 5 -#define ELFDATA2LSB 1 -#define ELFDATA2MSB 2 - -#define EI_CLASS 4 -#define ELFCLASS32 1 -#define ELFCLASS64 2 /* 64-bit objects */ - -#define EI_OSABI 7 -#define EI_ABIVERSION 8 - -#define ELFOSABI_AROS 15 - -#define PF_X (1 << 0) - -struct elfheader -{ - UBYTE ident[16]; - UWORD type; - UWORD machine; - ULONG version; - IPTR entry; - IPTR phoff; - IPTR shoff; - ULONG flags; - UWORD ehsize; - UWORD phentsize; - UWORD phnum; - UWORD shentsize; - UWORD shnum; - UWORD shstrndx; -} ATTRIBUTE_PACKED; - -struct sheader -{ - ULONG name; - ULONG type; - IPTR flags; - IPTR addr; - IPTR offset; - IPTR size; - ULONG link; - ULONG info; - IPTR addralign; - IPTR entsize; -} ATTRIBUTE_PACKED; - -#define PT_LOAD 1 - -struct pheader -{ - ULONG type; - ULONG offset; - IPTR vaddr; - IPTR paddr; - ULONG filesz; - ULONG memsz; - ULONG flags; - ULONG align; -} ATTRIBUTE_PACKED; - -struct symbol -{ - ULONG name; /* Offset of the name string in the string table */ - IPTR value; /* Varies; eg. the offset of the symbol in its hunk */ - IPTR size; /* How much memory does the symbol occupy */ - UBYTE info; /* What kind of symbol is this ? (global, variable, etc) */ - UBYTE other; /* undefined */ - UWORD shindex; /* In which section is the symbol defined ? */ -} ATTRIBUTE_PACKED; - -#define ELF_R_SYM(val) ((val) >> 8) -#define ELF_R_TYPE(val) ((val) & 0xff) -#define ELF_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) - -struct relo -{ - IPTR offset; /* Address of the relocation relative to the section it refers to */ - IPTR info; /* Type of the relocation */ - SIPTR addend; /* Constant addend used to compute value */ -}; - -/* Note: the conversion below is not in line with ELF specification and is fixed in GNU binutils since 2008 - * See: https://sourceware.org/bugzilla/show_bug.cgi?id=5900 - */ -/* convert section header number to array index */ -/*#define SHINDEX(n) \ - ((n) < SHN_LORESERVE ? (n) : ((n) <= SHN_HIRESERVE ? 0 : (n) - (SHN_HIRESERVE + 1 - SHN_LORESERVE)))*/ - -/* convert section header array index to section number */ -/*#define SHNUM(i) \ - ((i) < SHN_LORESERVE ? (i) : (i) + (SHN_HIRESERVE + 1 - SHN_LORESERVE))*/ - -/* m68k Machine's native values */ -#define AROS_ELF_CLASS ELFCLASS32 -#define AROS_ELF_DATA ELFDATA2MSB -#define AROS_ELF_MACHINE EM_68K -#define AROS_ELF_REL SHT_RELA - - -#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__ -# include -# define VA_START(args, lastarg) va_start(args, lastarg) -#else -# include -# define VA_START(args, lastarg) va_start(args) -#endif - -#ifdef PROTOTYPES -# define PARAMS(x) x -#else -# define PARAMS(x) () -#endif /* PROTOTYPES */ - -static void set_error(int err) -{ - errno = err; -} - -#if defined(DEBUG) && DEBUG -#define D(x) x -#define DB2(x) x -#else -#define D(x) -#define DB2(x) -#endif - -#if defined(_MSC_VER) -#define bug(fmt,...) fprintf(stderr, fmt , __VA_ARGS__ ) -#else -#define bug(fmt,args...) fprintf(stderr, fmt ,##args ) -#endif - -static int must_swap = -1; - -// hack for SHN_COMMON -static struct hunkheader *theBSS; -static int bssIndex; - - -static void eh_fixup(struct elfheader *eh) -{ - /* Endian swaps */ - if (eh->type == 256) { - must_swap = 1; - eh->type = ntohs(eh->type); - eh->machine = ntohs(eh->machine); - eh->version = ntohl(eh->version); - eh->entry = ntohl(eh->entry); - eh->phoff = ntohl(eh->phoff); - eh->shoff = ntohl(eh->shoff); - eh->flags = ntohl(eh->flags); - eh->ehsize = ntohs(eh->ehsize); - eh->phentsize = ntohs(eh->phentsize); - eh->phnum = ntohs(eh->phnum); - eh->shentsize = ntohs(eh->shentsize); - eh->shnum = ntohs(eh->shnum); - eh->shstrndx = ntohs(eh->shstrndx); - } else { - must_swap = 0; - } -} - -static void sh_fixup(struct sheader *sh, int n) -{ - if (must_swap == 0) - return; - - for (; n > 0; n--, sh++) { - sh->name = ntohl(sh->name); - sh->type = ntohl(sh->type); - sh->flags = ntohl(sh->flags); - sh->addr = ntohl(sh->addr); - sh->offset = ntohl(sh->offset); - sh->size = ntohl(sh->size); - sh->link = ntohl(sh->link); - sh->info = ntohl(sh->info); - sh->addralign = ntohl(sh->addralign); - sh->entsize = ntohl(sh->entsize); - } -} - -static void rel_fixup(struct relo *rel) -{ - if (must_swap == 0) - return; - - rel->offset = ntohl(rel->offset); - rel->info = ntohl(rel->info); - rel->addend = ntohl(rel->addend); -} - -void sym_fixup(struct symbol *sym) -{ - if (must_swap == 0) - return; - - sym->name = ntohl(sym->name); - sym->value = ntohl(sym->value); - sym->size = ntohl(sym->size); - sym->shindex = ntohs(sym->shindex); -} - -static void *load_block (int file,ULONG offset,ULONG size) -{ - ULONG lsize = (size + sizeof(ULONG) - 1) / sizeof(ULONG); - D(bug("[ELF2HUNK] Load Block\n")); - D(bug("[ELF2HUNK] (size=%d)\n",(int)size)); - ULONG *block = (ULONG *)malloc(lsize * sizeof(ULONG)); - if (block) { - block[lsize - 1] = 0; - lseek(file, offset, SEEK_SET); - if (read(file, block, size) == size) { - return block; - } - - free(block); - set_error(EIO); - } else - set_error(ENOMEM); - - return NULL; -} - -static ULONG read_shnum(int file, struct elfheader *eh) -{ - ULONG shnum = eh->shnum; - - /* the ELF header only uses 16 bits to store the count of section headers, - * so it can't handle more than 65535 headers. if the count is 0, and an - * offset is defined, then the real count can be found in the first - * section header (which always exists). - * - * similarly, if the string table index is SHN_XINDEX, then the actual - * index is found in the first section header also. - * - * see the System V ABI 2001-04-24 draft for more details. - */ - if (eh->shnum == 0) - { - struct sheader sh; - - if (eh->shoff == 0) { - set_error(ENOEXEC); - return 0; - } - - lseek(file, eh->shoff, SEEK_SET); - if (read(file, &sh, sizeof(sh)) != sizeof(sh)) - return 0; - - sh_fixup(&sh, 1); - - /* wider section header count is in the size field */ - shnum = sh.size; - - /* sanity, if they're still invalid then this isn't elf */ - if (shnum == 0) - set_error(ENOEXEC); - } - - return shnum; -} - -static int load_header(int file, struct elfheader *eh) -{ - lseek(file, 0, SEEK_SET); - if (read(file, eh, sizeof(struct elfheader)) != sizeof(struct elfheader)) { - D(bug("[ELF2HUNK] Can't read the %d byte ELF header\n", (int)sizeof(struct elfheader))); - return 0; - } - - eh_fixup(eh); - - if (eh->ident[0] != 0x7f || eh->ident[1] != 'E' || - eh->ident[2] != 'L' || eh->ident[3] != 'F') { - D(bug("[ELF2HUNK] Not an ELF object\n")); - return 0; - } - D(bug("[ELF2HUNK] ELF object\n")); - - /* WANT_CLASS should be defined for your target */ - if (eh->ident[EI_CLASS] != AROS_ELF_CLASS || - eh->ident[EI_VERSION] != EV_CURRENT || - eh->type != ET_REL || - eh->ident[EI_DATA] != AROS_ELF_DATA || - eh->machine != AROS_ELF_MACHINE) - { - D(bug("[ELF2HUNK] Object is of wrong type\n")); - D(bug("[ELF2HUNK] EI_CLASS is %d - should be %d\n", eh->ident[EI_CLASS] , AROS_ELF_CLASS )); - D(bug("[ELF2HUNK] EI_VERSION is %d - should be %d\n", eh->ident[EI_VERSION], EV_CURRENT )); - D(bug("[ELF2HUNK] type is %d - should be %d\n", eh->type , ET_REL )); - D(bug("[ELF2HUNK] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA] , AROS_ELF_DATA )); - D(bug("[ELF2HUNK] machine is %d - should be %d\n", eh->machine , AROS_ELF_MACHINE)); - - set_error(ENOEXEC); - return 0; - } - - return 1; -} - -struct hunkreloc { - ULONG shid; /* ELF hunk base to add to... */ - ULONG offset; /* offset in this hunk. */ - const char *symbol; -}; - -struct hunkheader { - ULONG type; - ULONG memflags; /* Memory flags */ - ULONG size; /* Size in ULONGs */ - char *data; - ULONG relocs; - int hunk; /* Allocatable hunk ID */ - struct hunkreloc *reloc; -}; - -static int relocate -( - struct elfheader *eh, - struct sheader *sh, - ULONG shrel_idx, - int symtab_shndx, - struct relo *rel, - struct hunkheader **hh -) -{ - struct sheader *shrel = &sh[shrel_idx]; - struct sheader *shsymtab = &sh[shrel->link]; - struct sheader *toreloc = &sh[shrel->info]; - - struct symbol *symtab = (struct symbol *)hh[shrel->link]->data; - struct hunkheader *h = hh[shrel->info]; - - /* - * Ignore relocs if the target section has no allocation. that can happen - * eg. with a .debug PROGBITS and a .rel.debug section - */ - D(bug("[ELF2HUNK] sh[%d].flags = 0x%x\n", (int)(shrel->info), (int)toreloc->flags)); - if (!(toreloc->flags & SHF_ALLOC)) - return 1; - - ULONG numrel = shrel->size / shrel->entsize; - ULONG i; - ULONG hrels; - - hrels = h->relocs; - h->relocs += numrel; - h->reloc = (struct hunkreloc *)realloc(h->reloc, h->relocs * sizeof(struct hunkreloc)); - struct hunkreloc *hrel = &h->reloc[hrels]; - - for (i=0; iinfo) == R_ARM_V4BX) - continue; -#endif - - struct symbol * symptr = &symtab[ELF_R_SYM(rel->info)]; - sym = *symptr; - sym_fixup(&sym); - offset = rel->offset; - symname = (const char *)(hh[shsymtab->link]->data + sym.name); - - if (sym.shindex != SHN_XINDEX) - shindex = sym.shindex; - - else { - if (symtab_shndx < 0) { - bug("[ELF2HUNK] got symbol with shndx 0xfff, but there's no symtab shndx table\n"); - set_error(EINVAL); - return 0; - } - shindex = ntohl(((ULONG *)hh[symtab_shndx]->data)[ELF_R_SYM(rel->info)]); - } - - D(bug("[ELF2HUNK] Processing %d symbol %s\n", (int)shindex, symname)); - - switch (shindex) - { - - case SHN_UNDEF: - if (ELF_R_TYPE(rel->info) != 0) { - bug("[ELF2HUNK] SHN_UNDEF symbol '%s', type %d unsupported\n", symname, ELF_R_TYPE(rel->info)); - set_error(EINVAL); - return 0; - } - break; - - case SHN_COMMON: - hunk = bssIndex; - value = theBSS->size; - theBSS->size += (sym.size + 3) & ~3; - - symptr->shindex = htons(bssIndex); - symptr->value = htonl(value); - break; - case SHN_ABS: - hunk = ~0; value = sym.value; - break; - - default: - hunk = shindex; - value = sym.value; - break; - } - - switch (ELF_R_TYPE(rel->info)) - { - case R_68K_32: - value += rel->addend; - break; - - case R_68K_PC32: - value += rel->addend - offset; - break; - - case R_68K_PC16: - bug("[ELF2HUNK] Unsupported relocation type R_68K_PC16\n"); - set_error(EINVAL); - return 0; - break; - - case R_68k_NONE: - break; - - default: - bug("[ELF2HUNK] Unrecognized relocation type %d %d\n", (int)i, (int)ELF_R_TYPE(rel->info)); - set_error(EINVAL); - return 0; - } - - D(bug("[ELF2HUNK] Hunk %d, offset 0x%x: base 0x%x\n", (int)hunk, (int)offset, (int)value)); - *(ULONG *)(h->data + offset) = htonl(value + ntohl(*(ULONG *)(h->data + offset))); - if (hunk == ~0) { - h->relocs--; - continue; - } - hrel->shid = hunk; - hrel->offset = offset; - hrel->symbol = symname; - hrel++; - } - - return 1; -} - -int reloc_cmp(const void *a, const void *b) -{ - const struct hunkreloc *ha = (const struct hunkreloc *)a, *hb = (const struct hunkreloc *)b; - - if (ha->shid != hb->shid) - return hb->shid - ha->shid; - return hb->offset - ha->offset; -} - -static int wlong(int fd, ULONG val) -{ - val = htonl(val); - return write(fd, &val, sizeof(val)); -} - -int sym_dump(int hunk_fd, struct sheader *sh, struct hunkheader **hh, int shid, int symtabndx) -{ - int i, err, syms; - struct symbol *sym = (struct symbol *)hh[symtabndx]->data; - struct sheader *symtab = &sh[symtabndx]; - - syms = symtab->size / sizeof(struct symbol); - - if (syms == 0) - return 1; - - wlong(hunk_fd, HUNK_SYMBOL); - wlong(hunk_fd, syms); - - /* Dump symbols for this hunk */ - for (i = 0; i < syms ; i++) { - struct symbol s; - const char *name; - int lsize; - - s = sym[i]; - sym_fixup(&s); - - if (s.shindex != shid) - continue; - - name = (const char *)(hh[symtab->link]->data + s.name); - D(bug("\t0x%08x: %s\n", (int)s.value, name)); - lsize = (strlen(name) + 4) / 4; - wlong(hunk_fd, lsize); - err = write(hunk_fd, name, lsize * 4); - if (err < 0) - return 0; - wlong(hunk_fd, s.value); - } - wlong(hunk_fd, 0); - - return 1; -} - -static void reloc_dump(int hunk_fd, struct hunkheader **hh, int h) -{ - int i; - - if (hh[h]->relocs == 0) - return; - - /* Sort the relocations by reference hunk id */ - qsort(hh[h]->reloc, hh[h]->relocs, sizeof(hh[h]->reloc[0]), reloc_cmp); - - wlong(hunk_fd, HUNK_RELOC32); - D(bug("\tHUNK_RELOC32: %d relocations\n", (int)hh[h]->relocs)); - - for (i = 0; i < hh[h]->relocs; ) { - int count; - int shid = hh[h]->reloc[i].shid; - for (count = i; count < hh[h]->relocs; count++) - if (hh[h]->reloc[count].shid != shid) - break; - count -= i; - wlong(hunk_fd, count); - D(bug("\t %d relocations relative to Hunk %d\n", count, hh[shid]->hunk)); - /* Convert from ELF hunk ID to AOS hunk ID */ - wlong(hunk_fd, hh[shid]->hunk); - for (; count > 0; i++, count--) { - D(bug("\t\t%d: 0x%08x %s\n", i, (int)hh[h]->reloc[i].offset, hh[h]->reloc[i].symbol)); - wlong(hunk_fd, hh[h]->reloc[i].offset); - } - } - wlong(hunk_fd, 0); -} - -static int copy_to(int in, int out) -{ - static char buff[64*1024]; - int len, err = 0; - - do { - len = read(in, buff, sizeof(buff)); - if (len < 0) { - perror("Can't read from input file\n"); - err = len; - } - if (len == 0) - break; - } while ((err = write(out, buff, len)) == len); - - if (err < 0) { - perror("Can't write to output file\n"); - return -errno; - } - - return 0; -} - -int elf2hunk(int file, int hunk_fd, const char *libname, int flags) -{ - const ATTRIBUTE_UNUSED char *names[3] = { "CODE", "DATA", "BSS" }; - struct hunkheader **hh; - struct elfheader eh; - struct sheader *sh; - char *strtab = 0; - int symtab_shndx = -1; - int err; - ULONG i; - BOOL exec_hunk_seen = FALSE; - ULONG int_shnum; - int hunks = 0; - - /* load and validate ELF header */ - D(bug("Load header\n")); - if ((flags & F_NOCONVERT) || !load_header(file, &eh)) { - /* If it's not an ELF, just copy it. - * - * This simplifies a number of mmakefiles - * for the m68k-amiga boot and ISO creation - */ - lseek(file, 0, SEEK_SET); - return (copy_to(file, hunk_fd) == 0) ? EXIT_SUCCESS : EXIT_FAILURE; - } - - D(bug("Read SHNum\n")); - int_shnum = read_shnum(file, &eh); - if (!int_shnum) - return EXIT_FAILURE; - - /* load section headers */ - D(bug("Load %d Section Headers @0x%08x\n", int_shnum, (int)eh.shoff)); - if (!(sh = (struct sheader *)load_block(file, eh.shoff, int_shnum * eh.shentsize))) - return EXIT_FAILURE; - - sh_fixup(sh, int_shnum); - - /* Looks like we have a valid executable. Generate a - * HUNK header set. Not all may be filled in. - */ - hh = (struct hunkheader **)calloc(sizeof(*hh), int_shnum); - - /* Look for the string table */ - D(bug("Look for string table\n")); - for (i = 0; i < int_shnum; i++) { - if (sh[i].type == SHT_STRTAB) { - strtab = (char *)load_block(file, sh[i].offset, sh[i].size); - break; - } - } - - /* Iterate over the section headers in order to do some stuff... */ - D(bug("Look for symbol tables\n")); - for (i = 0; i < int_shnum; i++) - { - /* - Load the symbol and string table(s). - - NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states - that only one symbol table per file is allowed. However, it - also states that this may change in future... we already handle it. - */ - D(bug("sh[%d].type = 0x%08x, .offset = 0x%08x, .size = 0x%08x\n", - (int)i, (int)sh[i].type, (int)sh[i].offset, (int)sh[i].size)); - if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB || sh[i].type == SHT_SYMTAB_SHNDX) - { - hh[i] = (struct hunkheader *)calloc(sizeof(struct hunkheader), 1); - hh[i]->type = (sh[i].type == SHT_SYMTAB) ? HUNK_SYMBOL : 0; - hh[i]->memflags = 0; - hh[i]->hunk = -1; - hh[i]->data = (char *)load_block(file, sh[i].offset, sh[i].size); - if (!hh[i]->data) - goto error; - - if (sh[i].type == SHT_SYMTAB_SHNDX) { - if (symtab_shndx == -1) - symtab_shndx = i; - else - D(bug("[ELF2HUNK] file contains multiple symtab shndx tables. only using the first one\n")); - } - } - else - /* Load the section in memory if needed, and make an hunk out of it */ - if (sh[i].flags & SHF_ALLOC && sh[i].size > 0) - { - hh[i] = (struct hunkheader *)calloc(sizeof(struct hunkheader), 1); - hh[i]->size = sh[i].size; - hh[i]->hunk = hunks++; - - if (sh[i].type == SHT_NOBITS) { - /* BSS area */ - hh[i]->type = HUNK_BSS; - hh[i]->memflags = 0; - hh[i]->data = NULL; - - if (theBSS == 0) { - theBSS = hh[i]; - bssIndex = i; - } - - } else { - if (sh[i].flags & SHF_EXECINSTR) { - hh[i]->type = HUNK_CODE; - exec_hunk_seen = TRUE; - } else { - hh[i]->type = HUNK_DATA; - } - hh[i]->data = (char *)load_block(file, sh[i].offset, sh[i].size); - } - - if (strtab) { - const char *nameext; - - D(bug("section %s\n", strtab + sh[i].name)); - nameext = strrchr(strtab + sh[i].name, '.'); - if (nameext) { - if (strcmp(nameext, ".MEMF_CHIP")==0) { - hh[i]->memflags |= MEMF_CHIP; - } else if (strcmp(nameext, ".MEMF_LOCAL")==0) { - hh[i]->memflags |= MEMF_LOCAL; - } else if (strcmp(nameext, ".MEMF_KICK")==0) { - hh[i]->memflags |= MEMF_KICK; - } else if (strcmp(nameext, ".MEMF_FAST")==0) { - hh[i]->memflags |= MEMF_FAST; - } - } - } - } - } - - /* Relocate the sections */ - D(bug("Convert relocation tables\n")); - for (i = 0; i < int_shnum; i++) - { - /* Does this relocation section refer to a hunk? If so, addr must be != 0 */ - if ((sh[i].type == AROS_ELF_REL) - && hh[sh[i].info] - && hh[sh[i].info]->data) - { - struct relo *reloc = (struct relo *)load_block(file, sh[i].offset, sh[i].size); - - if (!relocate(&eh, sh, i, symtab_shndx, reloc, hh)) - return EXIT_FAILURE; - - free(reloc); - } - } - - D(bug("HUNK_HEADER: \"%s\", hunks=%d, first=%d, last=%d\n", libname, hunks, 0, hunks-1)); - - wlong(hunk_fd, HUNK_HEADER); - if (libname == NULL) { - wlong(hunk_fd, 0); /* No name */ - } else { - int lsize = (strlen(libname) + 4) / 4; - wlong(hunk_fd, lsize); - err = write(hunk_fd, libname, lsize * 4); - if (err < 0) - return EXIT_FAILURE; - } - wlong(hunk_fd, hunks); - wlong(hunk_fd, 0); /* First hunk is #0 */ - wlong(hunk_fd, hunks - 1); /* Last hunk is hunks-1 */ - - /* Write all allocatable hunk sizes */ - for (i = 0; i < int_shnum; i++) { - ULONG count; - - if (hh[i]==NULL || hh[i]->hunk < 0) - continue; - - count = (hh[i]->size + 3) / 4; - switch (hh[i]->memflags) { - case MEMF_CHIP: - count |= HUNKF_CHIP; - break; - case MEMF_FAST: - count |= HUNKF_FAST; - break; - case 0: - break; - default: - count |= HUNKF_MEMFLAGS; - break; - } - - D(bug("\tHunk #%d, %s, lsize=%d\n", hh[i]->hunk, names[hh[i]->type - HUNK_CODE], (int)(hh[i]->size + 3) / 4)); // ? + 4 - wlong(hunk_fd, count); - - if ((count & HUNKF_MEMFLAGS) == HUNKF_MEMFLAGS) - wlong(hunk_fd, hh[i]->memflags | MEMF_PUBLIC | MEMF_CLEAR); - } - - /* Write all hunks */ - for (i = hunks = 0; i < int_shnum; i++) { - int s; - - if (hh[i]==NULL || hh[i]->hunk < 0) - continue; - - wlong(hunk_fd, hh[i]->type); - wlong(hunk_fd, (hh[i]->size + 3) / 4); - - switch (hh[i]->type) { - case HUNK_BSS: - D(bug("HUNK_BSS: %d longs\n", (int)((hh[i]->size + 3) / 4))); -if (0) { - for (s = 0; s < int_shnum; s++) { - if (hh[s] && hh[s]->type == HUNK_SYMBOL) - sym_dump(hunk_fd, sh, hh, i, s); - } -} - wlong(hunk_fd, HUNK_END); - hunks++; - break; - case HUNK_CODE: - case HUNK_DATA: - D(bug("#%d HUNK_%s: %d longs\n", hh[i]->hunk, hh[i]->type == HUNK_CODE ? "CODE" : "DATA", (int)((hh[i]->size + 3) / 4))); - err = write(hunk_fd, hh[i]->data, ((hh[i]->size + 3)/4)*4); - if (err < 0) - return EXIT_FAILURE; -if (0) { - for (s = 0; s < int_shnum; s++) { - if (hh[s] && hh[s]->type == HUNK_SYMBOL) - sym_dump(hunk_fd, sh, hh, i, s); - } -} - reloc_dump(hunk_fd, hh, i); - wlong(hunk_fd, HUNK_END); - D(bug("\tHUNK_END\n")); - break; - default: - D(bug("Unsupported allocatable hunk type %d\n", (int)hh[i]->type)); - return EXIT_FAILURE; - } - } - - /* Free all blocks */ - for (i = 0; i < int_shnum; i++) { - if (hh[i]) { - if (hh[i]->data) - free(hh[i]->data); - if (hh[i]->reloc) - free(hh[i]->reloc); - free(hh[i]); - } - } - free(hh); - free(sh); - - if (strtab) - free(strtab); - - D(bug("All good, all done.\n")); - return EXIT_SUCCESS; - -error: - return EXIT_FAILURE; -} - -static int copy(const char *src, const char *dst, int flags); - -static int copy_dir(const char *src, const char *dst, int flags) -{ - DIR *sdir; - struct dirent *de; - char spath[PATH_MAX], dpath[PATH_MAX]; - char *sp, *dp; - int sleft, dleft; - int err = EXIT_SUCCESS; - - sdir = opendir(src); - if (sdir == NULL) { - perror(src); - return EXIT_FAILURE; - } - - snprintf(spath, sizeof(spath), "%s/", src); - spath[sizeof(spath)-1] = 0; - sp = &spath[strlen(spath)]; - sleft = &spath[sizeof(spath)-1] - sp; - - snprintf(dpath, sizeof(dpath), "%s/", dst); - dpath[sizeof(dpath)-1] = 0; - dp = &dpath[strlen(dpath)]; - dleft = &dpath[sizeof(dpath)-1] - dp; - - while ((de = readdir(sdir)) != NULL) { - int eflags = 0; - - if ((strcmp(de->d_name, ".") == 0) || - (strcmp(de->d_name, "..") == 0)) - continue; - - /* Don't convert anything in a Development directory */ - if (strcasecmp(de->d_name, "Development") == 0) - eflags |= F_NOCONVERT; - - strncpy(sp, de->d_name, sleft); - sp[sleft-1] = 0; - strncpy(dp, de->d_name, dleft); - dp[dleft-1] = 0; - err = copy(spath, dpath, flags | eflags); - if (err != EXIT_SUCCESS) - break; - } - - closedir(sdir); - - return err; -} - -static int copy(const char *src, const char *dst, int flags) -{ - int src_fd, hunk_fd; - struct stat st; - int mode, ret; - - if (flags & F_VERBOSE) - printf("%s ->\n %s\n", src, dst); - - if (stat(src, &st) >= 0) { - mode = st.st_mode; - } else { - mode = 0755; - } - - if (S_ISDIR(mode)) { - unlink(dst); - mkdir(dst, mode); - return copy_dir(src, dst, flags); - } - - src_fd = open(src, O_RDONLY | O_BINARY); - if (src_fd < 0) { - perror(src); - return EXIT_FAILURE; - } - - if (strcmp(dst,"-") == 0) - hunk_fd = 1; /* stdout */ - else { - unlink(dst); - hunk_fd = open(dst, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, mode); - } - if (hunk_fd < 0) { - perror(dst); - return EXIT_FAILURE; - } - - ret = elf2hunk(src_fd, hunk_fd, NULL, flags); - if (ret != 0) - perror(src); - - close(src_fd); - if (hunk_fd != 1) - close(hunk_fd); - - return ret; -} - -int main(int argc, char **argv) -{ - int flags = 0; - - if (argc == 4 && strcmp(argv[1],"-v") == 0) { - flags |= F_VERBOSE; - argc--; - argv++; - } - - if (argc != 3) { - fprintf(stderr, "Usage:\n%s file.elf file.hunk\n", argv[0]); - fprintf(stderr, "%s src-dir dest-dir\n", argv[0]); - return EXIT_FAILURE; - } - - return copy(argv[1], argv[2], flags); -} +/* + Copyright © 1995-2001, The AROS Development Team. All rights reserved. +*/ + +#define PROTOTYPES +#define HAVE_STDARG_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define F_VERBOSE (1 << 0) +#define F_NOCONVERT (1 << 1) + +#if defined(_MSC_VER) + +#include +#include +#define ATTRIBUTE_PACKED +#define ATTRIBUTE_UNUSED +#define lseek _lseek +#define read _read +#define write _write +#define open _open +#define unlink _unlink +#define close _close +#define mkdir(a,b) _mkdir(a) + +#include "msdirent.h" +#include + +#define S_ISDIR(a) (a == 16895) + +#define strcasecmp strcmp + +#else +#include +#include +#define ATTRIBUTE_PACKED __attribute__((packed)) +#define ATTRIBUTE_UNUSED __attribute__((unused)) +#endif + +#if !defined(O_BINARY) +#define O_BINARY 0 +#endif + +#if (defined(__GNUC__))&&defined(WIN32) +#include +#define mkdir(path, mode) mkdir(path) +#elif !defined(_MSC_VER) +#include +typedef uint32_t ULONG; +typedef int BOOL; +#endif +typedef uint8_t UBYTE; +typedef uint16_t UWORD; +typedef uint32_t IPTR; +typedef int32_t SIPTR; +typedef char * STRPTR; + +#if !defined(FALSE)&&!defined(TRUE) +#define FALSE 0 +#define TRUE (!FALSE) +#endif + +/* Memory allocation flags */ +#define MEMF_ANY 0L +#define MEMF_PUBLIC (1L<<0) +#define MEMF_CHIP (1L<<1) +#define MEMF_FAST (1L<<2) +#define MEMF_EXECUTABLE (1L<<4) /* AmigaOS v4 compatible */ +#define MEMF_LOCAL (1L<<8) +#define MEMF_24BITDMA (1L<<9) +#define MEMF_KICK (1L<<10) +#define MEMF_31BIT (1L<<12) /* Low address space (<2GB). Effective only on 64 bit machines. */ +#define MEMF_CLEAR (1L<<16) /* Explicitly clear memory after allocation */ +#define MEMF_LARGEST (1L<<17) +#define MEMF_REVERSE (1L<<18) +#define MEMF_TOTAL (1L<<19) +#define MEMF_HWALIGNED (1L<<20) /* For AllocMem() - align address and size to physical page boundary */ +#define MEMF_SEM_PROTECTED (1L<<20) /* For CreatePool() - add semaphore protection to the pool */ +#define MEMF_NO_EXPUNGE (1L<<31) + +#define HUNKF_ADVISORY (1L<<29) +#define HUNKF_CHIP (1L<<30) +#define HUNKF_FAST (1L<<31) +#define HUNKF_MEMFLAGS (HUNKF_CHIP | HUNKF_FAST) + + +#define HUNK_CODE 1001 +#define HUNK_DATA 1002 +#define HUNK_BSS 1003 +#define HUNK_RELOC32 1004 +#define HUNK_SYMBOL 1008 +#define HUNK_END 1010 +#define HUNK_HEADER 1011 + +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SYMTAB_SHNDX 18 + +#define ET_REL 1 +#define ET_EXEC 2 + +#define EM_386 3 +#define EM_68K 4 +#define EM_PPC 20 +#define EM_ARM 40 +#define EM_X86_64 62 /* AMD x86-64 */ + +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 + +/* AMD x86-64 relocations. */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_32 10 +#define R_X86_64_32S 11 + +#define R_68k_NONE 0 +#define R_68K_32 1 +#define R_68K_PC32 4 +#define R_68K_PC16 5 + +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 +#define R_PPC_ADDR16_LO 4 +#define R_PPC_ADDR16_HA 6 +#define R_PPC_REL24 10 +#define R_PPC_REL32 26 +#define R_PPC_REL16_LO 250 +#define R_PPC_REL16_HA 252 + +#define R_ARM_NONE 0 +#define R_ARM_PC24 1 +#define R_ARM_ABS32 2 +#define R_ARM_CALL 28 +#define R_ARM_JUMP24 29 +#define R_ARM_V4BX 40 +#define R_ARM_PREL31 42 +#define R_ARM_MOVW_ABS_NC 43 +#define R_ARM_MOVT_ABS 44 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_XINDEX 0xffff +#define SHN_HIRESERVE 0xffff + +#define SHF_WRITE (1 << 0) +#define SHF_ALLOC (1 << 1) +#define SHF_EXECINSTR (1 << 2) + +#define ELF_ST_TYPE(i) ((i) & 0x0F) + +#define EI_VERSION 6 +#define EV_CURRENT 1 + +#define EI_DATA 5 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define EI_CLASS 4 +#define ELFCLASS32 1 +#define ELFCLASS64 2 /* 64-bit objects */ + +#define EI_OSABI 7 +#define EI_ABIVERSION 8 + +#define ELFOSABI_AROS 15 + +#define PF_X (1 << 0) + +struct elfheader +{ + UBYTE ident[16]; + UWORD type; + UWORD machine; + ULONG version; + IPTR entry; + IPTR phoff; + IPTR shoff; + ULONG flags; + UWORD ehsize; + UWORD phentsize; + UWORD phnum; + UWORD shentsize; + UWORD shnum; + UWORD shstrndx; +} ATTRIBUTE_PACKED; + +struct sheader +{ + ULONG name; + ULONG type; + IPTR flags; + IPTR addr; + IPTR offset; + IPTR size; + ULONG link; + ULONG info; + IPTR addralign; + IPTR entsize; +} ATTRIBUTE_PACKED; + +#define PT_LOAD 1 + +struct pheader +{ + ULONG type; + ULONG offset; + IPTR vaddr; + IPTR paddr; + ULONG filesz; + ULONG memsz; + ULONG flags; + ULONG align; +} ATTRIBUTE_PACKED; + +struct symbol +{ + ULONG name; /* Offset of the name string in the string table */ + IPTR value; /* Varies; eg. the offset of the symbol in its hunk */ + IPTR size; /* How much memory does the symbol occupy */ + UBYTE info; /* What kind of symbol is this ? (global, variable, etc) */ + UBYTE other; /* undefined */ + UWORD shindex; /* In which section is the symbol defined ? */ +} ATTRIBUTE_PACKED; + +#define ELF_R_SYM(val) ((val) >> 8) +#define ELF_R_TYPE(val) ((val) & 0xff) +#define ELF_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) + +struct relo +{ + IPTR offset; /* Address of the relocation relative to the section it refers to */ + IPTR info; /* Type of the relocation */ + SIPTR addend; /* Constant addend used to compute value */ +}; + +/* Note: the conversion below is not in line with ELF specification and is fixed in GNU binutils since 2008 + * See: https://sourceware.org/bugzilla/show_bug.cgi?id=5900 + */ +/* convert section header number to array index */ +/*#define SHINDEX(n) \ + ((n) < SHN_LORESERVE ? (n) : ((n) <= SHN_HIRESERVE ? 0 : (n) - (SHN_HIRESERVE + 1 - SHN_LORESERVE)))*/ + +/* convert section header array index to section number */ +/*#define SHNUM(i) \ + ((i) < SHN_LORESERVE ? (i) : (i) + (SHN_HIRESERVE + 1 - SHN_LORESERVE))*/ + +/* m68k Machine's native values */ +#define AROS_ELF_CLASS ELFCLASS32 +#define AROS_ELF_DATA ELFDATA2MSB +#define AROS_ELF_MACHINE EM_68K +#define AROS_ELF_REL SHT_RELA + + +#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__ +# include +# define VA_START(args, lastarg) va_start(args, lastarg) +#else +# include +# define VA_START(args, lastarg) va_start(args) +#endif + +#ifdef PROTOTYPES +# define PARAMS(x) x +#else +# define PARAMS(x) () +#endif /* PROTOTYPES */ + +static void set_error(int err) +{ + errno = err; +} + +#if defined(DEBUG) && DEBUG +#define D(x) x +#define DB2(x) x +#else +#define D(x) +#define DB2(x) +#endif + +#if defined(_MSC_VER) +#define bug(fmt,...) fprintf(stderr, fmt , __VA_ARGS__ ) +#else +#define bug(fmt,args...) fprintf(stderr, fmt ,##args ) +#endif + +static int must_swap = -1; + +// hack for SHN_COMMON +static struct hunkheader *theBSS; +static int bssIndex; + + +static void eh_fixup(struct elfheader *eh) +{ + /* Endian swaps */ + if (eh->type == 256) { + must_swap = 1; + eh->type = ntohs(eh->type); + eh->machine = ntohs(eh->machine); + eh->version = ntohl(eh->version); + eh->entry = ntohl(eh->entry); + eh->phoff = ntohl(eh->phoff); + eh->shoff = ntohl(eh->shoff); + eh->flags = ntohl(eh->flags); + eh->ehsize = ntohs(eh->ehsize); + eh->phentsize = ntohs(eh->phentsize); + eh->phnum = ntohs(eh->phnum); + eh->shentsize = ntohs(eh->shentsize); + eh->shnum = ntohs(eh->shnum); + eh->shstrndx = ntohs(eh->shstrndx); + } else { + must_swap = 0; + } +} + +static void sh_fixup(struct sheader *sh, int n) +{ + if (must_swap == 0) + return; + + for (; n > 0; n--, sh++) { + sh->name = ntohl(sh->name); + sh->type = ntohl(sh->type); + sh->flags = ntohl(sh->flags); + sh->addr = ntohl(sh->addr); + sh->offset = ntohl(sh->offset); + sh->size = ntohl(sh->size); + sh->link = ntohl(sh->link); + sh->info = ntohl(sh->info); + sh->addralign = ntohl(sh->addralign); + sh->entsize = ntohl(sh->entsize); + } +} + +static void rel_fixup(struct relo *rel) +{ + if (must_swap == 0) + return; + + rel->offset = ntohl(rel->offset); + rel->info = ntohl(rel->info); + rel->addend = ntohl(rel->addend); +} + +void sym_fixup(struct symbol *sym) +{ + if (must_swap == 0) + return; + + sym->name = ntohl(sym->name); + sym->value = ntohl(sym->value); + sym->size = ntohl(sym->size); + sym->shindex = ntohs(sym->shindex); +} + +static void *load_block (int file,ULONG offset,ULONG size) +{ + ULONG lsize = (size + sizeof(ULONG) - 1) / sizeof(ULONG); + D(bug("[ELF2HUNK] Load Block\n")); + D(bug("[ELF2HUNK] (size=%d)\n",(int)size)); + ULONG *block = (ULONG *)malloc(lsize * sizeof(ULONG)); + if (block) { + block[lsize - 1] = 0; + lseek(file, offset, SEEK_SET); + if (read(file, block, size) == size) { + return block; + } + + free(block); + set_error(EIO); + } else + set_error(ENOMEM); + + return NULL; +} + +static ULONG read_shnum(int file, struct elfheader *eh) +{ + ULONG shnum = eh->shnum; + + /* the ELF header only uses 16 bits to store the count of section headers, + * so it can't handle more than 65535 headers. if the count is 0, and an + * offset is defined, then the real count can be found in the first + * section header (which always exists). + * + * similarly, if the string table index is SHN_XINDEX, then the actual + * index is found in the first section header also. + * + * see the System V ABI 2001-04-24 draft for more details. + */ + if (eh->shnum == 0) + { + struct sheader sh; + + if (eh->shoff == 0) { + set_error(ENOEXEC); + return 0; + } + + lseek(file, eh->shoff, SEEK_SET); + if (read(file, &sh, sizeof(sh)) != sizeof(sh)) + return 0; + + sh_fixup(&sh, 1); + + /* wider section header count is in the size field */ + shnum = sh.size; + + /* sanity, if they're still invalid then this isn't elf */ + if (shnum == 0) + set_error(ENOEXEC); + } + + return shnum; +} + +static int load_header(int file, struct elfheader *eh) +{ + lseek(file, 0, SEEK_SET); + if (read(file, eh, sizeof(struct elfheader)) != sizeof(struct elfheader)) { + D(bug("[ELF2HUNK] Can't read the %d byte ELF header\n", (int)sizeof(struct elfheader))); + return 0; + } + + eh_fixup(eh); + + if (eh->ident[0] != 0x7f || eh->ident[1] != 'E' || + eh->ident[2] != 'L' || eh->ident[3] != 'F') { + D(bug("[ELF2HUNK] Not an ELF object\n")); + return 0; + } + D(bug("[ELF2HUNK] ELF object\n")); + + /* WANT_CLASS should be defined for your target */ + if (eh->ident[EI_CLASS] != AROS_ELF_CLASS || + eh->ident[EI_VERSION] != EV_CURRENT || + eh->type != ET_REL || + eh->ident[EI_DATA] != AROS_ELF_DATA || + eh->machine != AROS_ELF_MACHINE) + { + D(bug("[ELF2HUNK] Object is of wrong type\n")); + D(bug("[ELF2HUNK] EI_CLASS is %d - should be %d\n", eh->ident[EI_CLASS] , AROS_ELF_CLASS )); + D(bug("[ELF2HUNK] EI_VERSION is %d - should be %d\n", eh->ident[EI_VERSION], EV_CURRENT )); + D(bug("[ELF2HUNK] type is %d - should be %d\n", eh->type , ET_REL )); + D(bug("[ELF2HUNK] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA] , AROS_ELF_DATA )); + D(bug("[ELF2HUNK] machine is %d - should be %d\n", eh->machine , AROS_ELF_MACHINE)); + + set_error(ENOEXEC); + return 0; + } + + return 1; +} + +struct hunkreloc { + ULONG shid; /* ELF hunk base to add to... */ + ULONG offset; /* offset in this hunk. */ + const char *symbol; +}; + +struct hunkheader { + ULONG type; + ULONG memflags; /* Memory flags */ + ULONG size; /* Size in ULONGs */ + char *data; + ULONG relocs; + int hunk; /* Allocatable hunk ID */ + struct hunkreloc *reloc; +}; + +static int relocate +( + struct elfheader *eh, + struct sheader *sh, + ULONG shrel_idx, + int symtab_shndx, + struct relo *rel, + struct hunkheader **hh +) +{ + struct sheader *shrel = &sh[shrel_idx]; + struct sheader *shsymtab = &sh[shrel->link]; + struct sheader *toreloc = &sh[shrel->info]; + + struct symbol *symtab = (struct symbol *)hh[shrel->link]->data; + struct hunkheader *h = hh[shrel->info]; + + /* + * Ignore relocs if the target section has no allocation. that can happen + * eg. with a .debug PROGBITS and a .rel.debug section + */ + D(bug("[ELF2HUNK] sh[%d].flags = 0x%x\n", (int)(shrel->info), (int)toreloc->flags)); + if (!(toreloc->flags & SHF_ALLOC)) + return 1; + + ULONG numrel = shrel->size / shrel->entsize; + ULONG i; + ULONG hrels; + + hrels = h->relocs; + h->relocs += numrel; + h->reloc = (struct hunkreloc *)realloc(h->reloc, h->relocs * sizeof(struct hunkreloc)); + struct hunkreloc *hrel = &h->reloc[hrels]; + + for (i=0; iinfo) == R_ARM_V4BX) + continue; +#endif + + struct symbol * symptr = &symtab[ELF_R_SYM(rel->info)]; + sym = *symptr; + sym_fixup(&sym); + offset = rel->offset; + symname = (const char *)(hh[shsymtab->link]->data + sym.name); + + if (sym.shindex != SHN_XINDEX) + shindex = sym.shindex; + + else { + if (symtab_shndx < 0) { + bug("[ELF2HUNK] got symbol with shndx 0xfff, but there's no symtab shndx table\n"); + set_error(EINVAL); + return 0; + } + shindex = ntohl(((ULONG *)hh[symtab_shndx]->data)[ELF_R_SYM(rel->info)]); + } + + D(bug("[ELF2HUNK] Processing %d symbol %s\n", (int)shindex, symname)); + + switch (shindex) + { + + case SHN_UNDEF: + if (ELF_R_TYPE(rel->info) != 0) { + bug("[ELF2HUNK] SHN_UNDEF symbol '%s', type %d unsupported\n", symname, ELF_R_TYPE(rel->info)); + set_error(EINVAL); + return 0; + } + break; + + case SHN_COMMON: + hunk = bssIndex; + value = theBSS->size; + theBSS->size += (sym.size + 3) & ~3; + + symptr->shindex = htons(bssIndex); + symptr->value = htonl(value); + break; + case SHN_ABS: + hunk = ~0; value = sym.value; + break; + + default: + hunk = shindex; + value = sym.value; + break; + } + + switch (ELF_R_TYPE(rel->info)) + { + case R_68K_32: + value += rel->addend; + break; + + case R_68K_PC32: + value += rel->addend - offset; + break; + + case R_68K_PC16: + bug("[ELF2HUNK] Unsupported relocation type R_68K_PC16\n"); + set_error(EINVAL); + return 0; + break; + + case R_68k_NONE: + break; + + default: + bug("[ELF2HUNK] Unrecognized relocation type %d %d\n", (int)i, (int)ELF_R_TYPE(rel->info)); + set_error(EINVAL); + return 0; + } + + D(bug("[ELF2HUNK] Hunk %d, offset 0x%x: base 0x%x\n", (int)hunk, (int)offset, (int)value)); + *(ULONG *)(h->data + offset) = htonl(value + ntohl(*(ULONG *)(h->data + offset))); + if (hunk == ~0) { + h->relocs--; + continue; + } + hrel->shid = hunk; + hrel->offset = offset; + hrel->symbol = symname; + hrel++; + } + + return 1; +} + +int reloc_cmp(const void *a, const void *b) +{ + const struct hunkreloc *ha = (const struct hunkreloc *)a, *hb = (const struct hunkreloc *)b; + + if (ha->shid != hb->shid) + return hb->shid - ha->shid; + return hb->offset - ha->offset; +} + +static int wlong(int fd, ULONG val) +{ + val = htonl(val); + return write(fd, &val, sizeof(val)); +} + +int sym_dump(int hunk_fd, struct sheader *sh, struct hunkheader **hh, int shid, int symtabndx) +{ + int i, err, syms; + struct symbol *sym = (struct symbol *)hh[symtabndx]->data; + struct sheader *symtab = &sh[symtabndx]; + + syms = symtab->size / sizeof(struct symbol); + + if (syms == 0) + return 1; + + wlong(hunk_fd, HUNK_SYMBOL); + wlong(hunk_fd, syms); + + /* Dump symbols for this hunk */ + for (i = 0; i < syms ; i++) { + struct symbol s; + const char *name; + int lsize; + + s = sym[i]; + sym_fixup(&s); + + if (s.shindex != shid) + continue; + + name = (const char *)(hh[symtab->link]->data + s.name); + D(bug("\t0x%08x: %s\n", (int)s.value, name)); + lsize = (strlen(name) + 4) / 4; + wlong(hunk_fd, lsize); + err = write(hunk_fd, name, lsize * 4); + if (err < 0) + return 0; + wlong(hunk_fd, s.value); + } + wlong(hunk_fd, 0); + + return 1; +} + +static void reloc_dump(int hunk_fd, struct hunkheader **hh, int h) +{ + int i; + + if (hh[h]->relocs == 0) + return; + + /* Sort the relocations by reference hunk id */ + qsort(hh[h]->reloc, hh[h]->relocs, sizeof(hh[h]->reloc[0]), reloc_cmp); + + wlong(hunk_fd, HUNK_RELOC32); + D(bug("\tHUNK_RELOC32: %d relocations\n", (int)hh[h]->relocs)); + + for (i = 0; i < hh[h]->relocs; ) { + int count; + int shid = hh[h]->reloc[i].shid; + for (count = i; count < hh[h]->relocs; count++) + if (hh[h]->reloc[count].shid != shid) + break; + count -= i; + wlong(hunk_fd, count); + D(bug("\t %d relocations relative to Hunk %d\n", count, hh[shid]->hunk)); + /* Convert from ELF hunk ID to AOS hunk ID */ + wlong(hunk_fd, hh[shid]->hunk); + for (; count > 0; i++, count--) { + D(bug("\t\t%d: 0x%08x %s\n", i, (int)hh[h]->reloc[i].offset, hh[h]->reloc[i].symbol)); + wlong(hunk_fd, hh[h]->reloc[i].offset); + } + } + wlong(hunk_fd, 0); +} + +static int copy_to(int in, int out) +{ + static char buff[64*1024]; + int len, err = 0; + + do { + len = read(in, buff, sizeof(buff)); + if (len < 0) { + perror("Can't read from input file\n"); + err = len; + } + if (len == 0) + break; + } while ((err = write(out, buff, len)) == len); + + if (err < 0) { + perror("Can't write to output file\n"); + return -errno; + } + + return 0; +} + +int elf2hunk(int file, int hunk_fd, const char *libname, int flags) +{ + const ATTRIBUTE_UNUSED char *names[3] = { "CODE", "DATA", "BSS" }; + struct hunkheader **hh; + struct elfheader eh; + struct sheader *sh; + char *strtab = 0; + int symtab_shndx = -1; + int err; + ULONG i; + BOOL exec_hunk_seen = FALSE; + ULONG int_shnum; + int hunks = 0; + + /* load and validate ELF header */ + D(bug("Load header\n")); + if ((flags & F_NOCONVERT) || !load_header(file, &eh)) { + /* If it's not an ELF, just copy it. + * + * This simplifies a number of mmakefiles + * for the m68k-amiga boot and ISO creation + */ + lseek(file, 0, SEEK_SET); + return (copy_to(file, hunk_fd) == 0) ? EXIT_SUCCESS : EXIT_FAILURE; + } + + D(bug("Read SHNum\n")); + int_shnum = read_shnum(file, &eh); + if (!int_shnum) + return EXIT_FAILURE; + + /* load section headers */ + D(bug("Load %d Section Headers @0x%08x\n", int_shnum, (int)eh.shoff)); + if (!(sh = (struct sheader *)load_block(file, eh.shoff, int_shnum * eh.shentsize))) + return EXIT_FAILURE; + + sh_fixup(sh, int_shnum); + + /* Looks like we have a valid executable. Generate a + * HUNK header set. Not all may be filled in. + */ + hh = (struct hunkheader **)calloc(sizeof(*hh), int_shnum); + + /* Look for the string table */ + D(bug("Look for string table\n")); + for (i = 0; i < int_shnum; i++) { + if (sh[i].type == SHT_STRTAB) { + strtab = (char *)load_block(file, sh[i].offset, sh[i].size); + break; + } + } + + /* Iterate over the section headers in order to do some stuff... */ + D(bug("Look for symbol tables\n")); + for (i = 0; i < int_shnum; i++) + { + /* + Load the symbol and string table(s). + + NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states + that only one symbol table per file is allowed. However, it + also states that this may change in future... we already handle it. + */ + D(bug("sh[%d].type = 0x%08x, .offset = 0x%08x, .size = 0x%08x\n", + (int)i, (int)sh[i].type, (int)sh[i].offset, (int)sh[i].size)); + if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB || sh[i].type == SHT_SYMTAB_SHNDX) + { + hh[i] = (struct hunkheader *)calloc(sizeof(struct hunkheader), 1); + hh[i]->type = (sh[i].type == SHT_SYMTAB) ? HUNK_SYMBOL : 0; + hh[i]->memflags = 0; + hh[i]->hunk = -1; + hh[i]->data = (char *)load_block(file, sh[i].offset, sh[i].size); + if (!hh[i]->data) + goto error; + + if (sh[i].type == SHT_SYMTAB_SHNDX) { + if (symtab_shndx == -1) + symtab_shndx = i; + else + D(bug("[ELF2HUNK] file contains multiple symtab shndx tables. only using the first one\n")); + } + } + else + /* Load the section in memory if needed, and make an hunk out of it */ + if (sh[i].flags & SHF_ALLOC && sh[i].size > 0) + { + hh[i] = (struct hunkheader *)calloc(sizeof(struct hunkheader), 1); + hh[i]->size = sh[i].size; + hh[i]->hunk = hunks++; + + if (sh[i].type == SHT_NOBITS) { + /* BSS area */ + hh[i]->type = HUNK_BSS; + hh[i]->memflags = 0; + hh[i]->data = NULL; + + if (theBSS == 0) { + theBSS = hh[i]; + bssIndex = i; + } + + } else { + if (sh[i].flags & SHF_EXECINSTR) { + hh[i]->type = HUNK_CODE; + exec_hunk_seen = TRUE; + } else { + hh[i]->type = HUNK_DATA; + } + hh[i]->data = (char *)load_block(file, sh[i].offset, sh[i].size); + } + + if (strtab) { + const char *nameext; + + D(bug("section %s\n", strtab + sh[i].name)); + nameext = strrchr(strtab + sh[i].name, '.'); + if (nameext) { + if (strcmp(nameext, ".MEMF_CHIP")==0) { + hh[i]->memflags |= MEMF_CHIP; + } else if (strcmp(nameext, ".MEMF_LOCAL")==0) { + hh[i]->memflags |= MEMF_LOCAL; + } else if (strcmp(nameext, ".MEMF_KICK")==0) { + hh[i]->memflags |= MEMF_KICK; + } else if (strcmp(nameext, ".MEMF_FAST")==0) { + hh[i]->memflags |= MEMF_FAST; + } + } + } + } + } + + /* Relocate the sections */ + D(bug("Convert relocation tables\n")); + for (i = 0; i < int_shnum; i++) + { + /* Does this relocation section refer to a hunk? If so, addr must be != 0 */ + if ((sh[i].type == AROS_ELF_REL) + && hh[sh[i].info] + && hh[sh[i].info]->data) + { + struct relo *reloc = (struct relo *)load_block(file, sh[i].offset, sh[i].size); + + if (!relocate(&eh, sh, i, symtab_shndx, reloc, hh)) + return EXIT_FAILURE; + + free(reloc); + } + } + + D(bug("HUNK_HEADER: \"%s\", hunks=%d, first=%d, last=%d\n", libname, hunks, 0, hunks-1)); + + wlong(hunk_fd, HUNK_HEADER); + if (libname == NULL) { + wlong(hunk_fd, 0); /* No name */ + } else { + int lsize = (strlen(libname) + 4) / 4; + wlong(hunk_fd, lsize); + err = write(hunk_fd, libname, lsize * 4); + if (err < 0) + return EXIT_FAILURE; + } + wlong(hunk_fd, hunks); + wlong(hunk_fd, 0); /* First hunk is #0 */ + wlong(hunk_fd, hunks - 1); /* Last hunk is hunks-1 */ + + /* Write all allocatable hunk sizes */ + for (i = 0; i < int_shnum; i++) { + ULONG count; + + if (hh[i]==NULL || hh[i]->hunk < 0) + continue; + + count = (hh[i]->size + 3) / 4; + switch (hh[i]->memflags) { + case MEMF_CHIP: + count |= HUNKF_CHIP; + break; + case MEMF_FAST: + count |= HUNKF_FAST; + break; + case 0: + break; + default: + count |= HUNKF_MEMFLAGS; + break; + } + + D(bug("\tHunk #%d, %s, lsize=%d\n", hh[i]->hunk, names[hh[i]->type - HUNK_CODE], (int)(hh[i]->size + 3) / 4)); // ? + 4 + wlong(hunk_fd, count); + + if ((count & HUNKF_MEMFLAGS) == HUNKF_MEMFLAGS) + wlong(hunk_fd, hh[i]->memflags | MEMF_PUBLIC | MEMF_CLEAR); + } + + /* Write all hunks */ + for (i = hunks = 0; i < int_shnum; i++) { + int s; + + if (hh[i]==NULL || hh[i]->hunk < 0) + continue; + + wlong(hunk_fd, hh[i]->type); + wlong(hunk_fd, (hh[i]->size + 3) / 4); + + switch (hh[i]->type) { + case HUNK_BSS: + D(bug("HUNK_BSS: %d longs\n", (int)((hh[i]->size + 3) / 4))); +if (0) { + for (s = 0; s < int_shnum; s++) { + if (hh[s] && hh[s]->type == HUNK_SYMBOL) + sym_dump(hunk_fd, sh, hh, i, s); + } +} + wlong(hunk_fd, HUNK_END); + hunks++; + break; + case HUNK_CODE: + case HUNK_DATA: + D(bug("#%d HUNK_%s: %d longs\n", hh[i]->hunk, hh[i]->type == HUNK_CODE ? "CODE" : "DATA", (int)((hh[i]->size + 3) / 4))); + err = write(hunk_fd, hh[i]->data, ((hh[i]->size + 3)/4)*4); + if (err < 0) + return EXIT_FAILURE; +if (0) { + for (s = 0; s < int_shnum; s++) { + if (hh[s] && hh[s]->type == HUNK_SYMBOL) + sym_dump(hunk_fd, sh, hh, i, s); + } +} + reloc_dump(hunk_fd, hh, i); + wlong(hunk_fd, HUNK_END); + D(bug("\tHUNK_END\n")); + break; + default: + D(bug("Unsupported allocatable hunk type %d\n", (int)hh[i]->type)); + return EXIT_FAILURE; + } + } + + /* Free all blocks */ + for (i = 0; i < int_shnum; i++) { + if (hh[i]) { + if (hh[i]->data) + free(hh[i]->data); + if (hh[i]->reloc) + free(hh[i]->reloc); + free(hh[i]); + } + } + free(hh); + free(sh); + + if (strtab) + free(strtab); + + D(bug("All good, all done.\n")); + return EXIT_SUCCESS; + +error: + return EXIT_FAILURE; +} + +static int copy(const char *src, const char *dst, int flags); + +static int copy_dir(const char *src, const char *dst, int flags) +{ + DIR *sdir; + struct dirent *de; + char spath[PATH_MAX], dpath[PATH_MAX]; + char *sp, *dp; + int sleft, dleft; + int err = EXIT_SUCCESS; + + sdir = opendir(src); + if (sdir == NULL) { + perror(src); + return EXIT_FAILURE; + } + + snprintf(spath, sizeof(spath), "%s/", src); + spath[sizeof(spath)-1] = 0; + sp = &spath[strlen(spath)]; + sleft = &spath[sizeof(spath)-1] - sp; + + snprintf(dpath, sizeof(dpath), "%s/", dst); + dpath[sizeof(dpath)-1] = 0; + dp = &dpath[strlen(dpath)]; + dleft = &dpath[sizeof(dpath)-1] - dp; + + while ((de = readdir(sdir)) != NULL) { + int eflags = 0; + + if ((strcmp(de->d_name, ".") == 0) || + (strcmp(de->d_name, "..") == 0)) + continue; + + /* Don't convert anything in a Development directory */ + if (strcasecmp(de->d_name, "Development") == 0) + eflags |= F_NOCONVERT; + + strncpy(sp, de->d_name, sleft); + sp[sleft-1] = 0; + strncpy(dp, de->d_name, dleft); + dp[dleft-1] = 0; + err = copy(spath, dpath, flags | eflags); + if (err != EXIT_SUCCESS) + break; + } + + closedir(sdir); + + return err; +} + +static int copy(const char *src, const char *dst, int flags) +{ + int src_fd, hunk_fd; + struct stat st; + int mode, ret; + + if (flags & F_VERBOSE) + printf("%s ->\n %s\n", src, dst); + + if (stat(src, &st) >= 0) { + mode = st.st_mode; + } else { + mode = 0755; + } + + if (S_ISDIR(mode)) { + unlink(dst); + mkdir(dst, mode); + return copy_dir(src, dst, flags); + } + + src_fd = open(src, O_RDONLY | O_BINARY); + if (src_fd < 0) { + perror(src); + return EXIT_FAILURE; + } + + if (strcmp(dst,"-") == 0) + hunk_fd = 1; /* stdout */ + else { + unlink(dst); + hunk_fd = open(dst, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, mode); + } + if (hunk_fd < 0) { + perror(dst); + return EXIT_FAILURE; + } + + ret = elf2hunk(src_fd, hunk_fd, NULL, flags); + if (ret != 0) + perror(src); + + close(src_fd); + if (hunk_fd != 1) + close(hunk_fd); + + return ret; +} + +int main(int argc, char **argv) +{ + int flags = 0; + + if (argc == 4 && strcmp(argv[1],"-v") == 0) { + flags |= F_VERBOSE; + argc--; + argv++; + } + + if (argc != 3) { + fprintf(stderr, "Usage:\n%s file.elf file.hunk\n", argv[0]); + fprintf(stderr, "%s src-dir dest-dir\n", argv[0]); + return EXIT_FAILURE; + } + + return copy(argv[1], argv[2], flags); +}