Import SB128-v5.24 to main branch
[AROS.git] / tools / elf2hunk / elf2hunk.c
blobfe418812d445c4be3ba9c4a8d86443d7b9046a26
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define PROTOTYPES
7 #define HAVE_STDARG_H
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <stdint.h>
13 #include <assert.h>
14 #include <ctype.h>
15 #include <errno.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <limits.h>
19 #include <dirent.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
24 #define F_VERBOSE (1 << 0)
25 #define F_NOCONVERT (1 << 1)
27 #if defined(__GNUC__)&&defined(WIN32)
28 #include <winsock2.h>
29 #define mkdir(path, mode) mkdir(path)
30 #else
31 #include <arpa/inet.h>
32 typedef uint32_t ULONG;
33 typedef int BOOL;
34 #endif
35 typedef uint8_t UBYTE;
36 typedef uint16_t UWORD;
37 typedef uint32_t IPTR;
38 typedef int32_t SIPTR;
39 typedef char * STRPTR;
41 #define SysBase 0x0004
43 #if !defined(FALSE)&&!defined(TRUE)
44 #define FALSE 0
45 #define TRUE (!FALSE)
46 #endif
48 #define HUNK_CODE 1001
49 #define HUNK_DATA 1002
50 #define HUNK_BSS 1003
51 #define HUNK_RELOC32 1004
52 #define HUNK_SYMBOL 1008
53 #define HUNK_END 1010
54 #define HUNK_HEADER 1011
56 #define SHT_PROGBITS 1
57 #define SHT_SYMTAB 2
58 #define SHT_STRTAB 3
59 #define SHT_RELA 4
60 #define SHT_NOBITS 8
61 #define SHT_REL 9
62 #define SHT_SYMTAB_SHNDX 18
64 #define ET_REL 1
65 #define ET_EXEC 2
67 #define EM_386 3
68 #define EM_68K 4
69 #define EM_PPC 20
70 #define EM_ARM 40
71 #define EM_X86_64 62 /* AMD x86-64 */
73 #define R_386_NONE 0
74 #define R_386_32 1
75 #define R_386_PC32 2
77 /* AMD x86-64 relocations. */
78 #define R_X86_64_NONE 0 /* No reloc */
79 #define R_X86_64_64 1 /* Direct 64 bit */
80 #define R_X86_64_PC32 2 /* PC relative 32 bit signed */
81 #define R_X86_64_32 10
82 #define R_X86_64_32S 11
84 #define R_68k_NONE 0
85 #define R_68K_32 1
86 #define R_68K_PC32 4
87 #define R_68K_PC16 5
89 #define R_PPC_NONE 0
90 #define R_PPC_ADDR32 1
91 #define R_PPC_ADDR16_LO 4
92 #define R_PPC_ADDR16_HA 6
93 #define R_PPC_REL24 10
94 #define R_PPC_REL32 26
95 #define R_PPC_REL16_LO 250
96 #define R_PPC_REL16_HA 252
98 #define R_ARM_NONE 0
99 #define R_ARM_PC24 1
100 #define R_ARM_ABS32 2
101 #define R_ARM_CALL 28
102 #define R_ARM_JUMP24 29
103 #define R_ARM_V4BX 40
104 #define R_ARM_PREL31 42
105 #define R_ARM_MOVW_ABS_NC 43
106 #define R_ARM_MOVT_ABS 44
108 #define STT_NOTYPE 0
109 #define STT_OBJECT 1
110 #define STT_FUNC 2
111 #define STT_SECTION 3
112 #define STT_FILE 4
113 #define STT_LOPROC 13
114 #define STT_HIPROC 15
116 #define SHN_UNDEF 0
117 #define SHN_LORESERVE 0xff00
118 #define SHN_ABS 0xfff1
119 #define SHN_COMMON 0xfff2
120 #define SHN_XINDEX 0xffff
121 #define SHN_HIRESERVE 0xffff
123 #define SHF_WRITE (1 << 0)
124 #define SHF_ALLOC (1 << 1)
125 #define SHF_EXECINSTR (1 << 2)
127 #define ELF_ST_TYPE(i) ((i) & 0x0F)
129 #define EI_VERSION 6
130 #define EV_CURRENT 1
132 #define EI_DATA 5
133 #define ELFDATA2LSB 1
134 #define ELFDATA2MSB 2
136 #define EI_CLASS 4
137 #define ELFCLASS32 1
138 #define ELFCLASS64 2 /* 64-bit objects */
140 #define EI_OSABI 7
141 #define EI_ABIVERSION 8
143 #define ELFOSABI_AROS 15
145 #define PF_X (1 << 0)
147 struct elfheader
149 UBYTE ident[16];
150 UWORD type;
151 UWORD machine;
152 ULONG version;
153 IPTR entry;
154 IPTR phoff;
155 IPTR shoff;
156 ULONG flags;
157 UWORD ehsize;
158 UWORD phentsize;
159 UWORD phnum;
160 UWORD shentsize;
161 UWORD shnum;
162 UWORD shstrndx;
163 } __attribute__((packed));
165 struct sheader
167 ULONG name;
168 ULONG type;
169 IPTR flags;
170 IPTR addr;
171 IPTR offset;
172 IPTR size;
173 ULONG link;
174 ULONG info;
175 IPTR addralign;
176 IPTR entsize;
177 } __attribute__((packed));
179 #define PT_LOAD 1
181 struct pheader
183 ULONG type;
184 ULONG offset;
185 IPTR vaddr;
186 IPTR paddr;
187 ULONG filesz;
188 ULONG memsz;
189 ULONG flags;
190 ULONG align;
191 } __attribute__((packed));
193 struct symbol
195 ULONG name; /* Offset of the name string in the string table */
196 IPTR value; /* Varies; eg. the offset of the symbol in its hunk */
197 IPTR size; /* How much memory does the symbol occupy */
198 UBYTE info; /* What kind of symbol is this ? (global, variable, etc) */
199 UBYTE other; /* undefined */
200 UWORD shindex; /* In which section is the symbol defined ? */
201 } __attribute__((packed));
203 #define ELF_R_SYM(val) ((val) >> 8)
204 #define ELF_R_TYPE(val) ((val) & 0xff)
205 #define ELF_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
207 struct relo
209 IPTR offset; /* Address of the relocation relative to the section it refers to */
210 IPTR info; /* Type of the relocation */
211 SIPTR addend; /* Constant addend used to compute value */
214 /* convert section header number to array index */
215 #define SHINDEX(n) \
216 ((n) < SHN_LORESERVE ? (n) : ((n) <= SHN_HIRESERVE ? 0 : (n) - (SHN_HIRESERVE + 1 - SHN_LORESERVE)))
218 /* convert section header array index to section number */
219 #define SHNUM(i) \
220 ((i) < SHN_LORESERVE ? (i) : (i) + (SHN_HIRESERVE + 1 - SHN_LORESERVE))
222 /* m68k Machine's native values */
223 #define AROS_ELF_CLASS ELFCLASS32
224 #define AROS_ELF_DATA ELFDATA2MSB
225 #define AROS_ELF_MACHINE EM_68K
226 #define AROS_ELF_REL SHT_RELA
229 #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
230 # include <stdarg.h>
231 # define VA_START(args, lastarg) va_start(args, lastarg)
232 #else
233 # include <varargs.h>
234 # define VA_START(args, lastarg) va_start(args)
235 #endif
237 #ifdef PROTOTYPES
238 # define PARAMS(x) x
239 #else
240 # define PARAMS(x) ()
241 #endif /* PROTOTYPES */
243 static void set_error(int err)
245 errno = err;
248 #if defined(DEBUG) && DEBUG
249 #define D(x) x
250 #define DB2(x) x
251 #else
252 #define D(x)
253 #define DB2(x)
254 #endif
255 #define bug(fmt,args...) fprintf(stderr, fmt ,##args )
257 static int must_swap = -1;
259 static void eh_fixup(struct elfheader *eh)
261 /* Endian swaps */
262 if (eh->type == 256) {
263 must_swap = 1;
264 eh->type = ntohs(eh->type);
265 eh->machine = ntohs(eh->machine);
266 eh->version = ntohl(eh->version);
267 eh->entry = ntohl(eh->entry);
268 eh->phoff = ntohl(eh->phoff);
269 eh->shoff = ntohl(eh->shoff);
270 eh->flags = ntohl(eh->flags);
271 eh->ehsize = ntohs(eh->ehsize);
272 eh->phentsize = ntohs(eh->phentsize);
273 eh->phnum = ntohs(eh->phnum);
274 eh->shentsize = ntohs(eh->shentsize);
275 eh->shnum = ntohs(eh->shnum);
276 eh->shstrndx = ntohs(eh->shstrndx);
277 } else {
278 must_swap = 0;
282 static void sh_fixup(struct sheader *sh, int n)
284 if (must_swap == 0)
285 return;
287 for (; n > 0; n--, sh++) {
288 sh->name = ntohl(sh->name);
289 sh->type = ntohl(sh->type);
290 sh->flags = ntohl(sh->flags);
291 sh->addr = ntohl(sh->addr);
292 sh->offset = ntohl(sh->offset);
293 sh->size = ntohl(sh->size);
294 sh->link = ntohl(sh->link);
295 sh->info = ntohl(sh->info);
296 sh->addralign = ntohl(sh->addralign);
297 sh->entsize = ntohl(sh->entsize);
301 static void rel_fixup(struct relo *rel)
303 if (must_swap == 0)
304 return;
306 rel->offset = ntohl(rel->offset);
307 rel->info = ntohl(rel->info);
308 rel->addend = ntohl(rel->addend);
311 void sym_fixup(struct symbol *sym)
313 if (must_swap == 0)
314 return;
316 sym->name = ntohl(sym->name);
317 sym->value = ntohl(sym->value);
318 sym->size = ntohl(sym->size);
319 sym->shindex = ntohs(sym->shindex);
322 static void *load_block (int file,ULONG offset,ULONG size)
324 ULONG lsize = (size + sizeof(ULONG) - 1) / sizeof(ULONG);
325 D(bug("[ELF2HUNK] Load Block\n"));
326 D(bug("[ELF2HUNK] (size=%d)\n",(int)size));
327 void *block = malloc(lsize * sizeof(ULONG));
328 if (block) {
329 lseek(file, offset, SEEK_SET);
330 if (read(file, block, size) == size) {
331 return block;
334 free(block);
335 set_error(EIO);
336 } else
337 set_error(ENOMEM);
339 return NULL;
342 static ULONG read_shnum(int file, struct elfheader *eh)
344 ULONG shnum = eh->shnum;
346 /* the ELF header only uses 16 bits to store the count of section headers,
347 * so it can't handle more than 65535 headers. if the count is 0, and an
348 * offset is defined, then the real count can be found in the first
349 * section header (which always exists).
351 * similarly, if the string table index is SHN_XINDEX, then the actual
352 * index is found in the first section header also.
354 * see the System V ABI 2001-04-24 draft for more details.
356 if (eh->shnum == 0)
358 struct sheader sh;
360 if (eh->shoff == 0) {
361 set_error(ENOEXEC);
362 return 0;
365 lseek(file, eh->shoff, SEEK_SET);
366 if (read(file, &sh, sizeof(sh)) != sizeof(sh))
367 return 0;
369 sh_fixup(&sh, 1);
371 /* wider section header count is in the size field */
372 shnum = sh.size;
374 /* sanity, if they're still invalid then this isn't elf */
375 if (shnum == 0)
376 set_error(ENOEXEC);
379 return shnum;
382 static int load_header(int file, struct elfheader *eh)
384 lseek(file, 0, SEEK_SET);
385 if (read(file, eh, sizeof(struct elfheader)) != sizeof(struct elfheader)) {
386 D(bug("[ELF2HUNK] Can't read the %d byte ELF header\n", (int)sizeof(struct elfheader)));
387 return 0;
390 eh_fixup(eh);
392 if (eh->ident[0] != 0x7f || eh->ident[1] != 'E' ||
393 eh->ident[2] != 'L' || eh->ident[3] != 'F') {
394 D(bug("[ELF2HUNK] Not an ELF object\n"));
395 return 0;
397 D(bug("[ELF2HUNK] ELF object\n"));
399 /* WANT_CLASS should be defined for your target */
400 if (eh->ident[EI_CLASS] != AROS_ELF_CLASS ||
401 eh->ident[EI_VERSION] != EV_CURRENT ||
402 eh->type != ET_REL ||
403 eh->ident[EI_DATA] != AROS_ELF_DATA ||
404 eh->machine != AROS_ELF_MACHINE)
406 D(bug("[ELF2HUNK] Object is of wrong type\n"));
407 D(bug("[ELF2HUNK] EI_CLASS is %d - should be %d\n", eh->ident[EI_CLASS] , AROS_ELF_CLASS ));
408 D(bug("[ELF2HUNK] EI_VERSION is %d - should be %d\n", eh->ident[EI_VERSION], EV_CURRENT ));
409 D(bug("[ELF2HUNK] type is %d - should be %d\n", eh->type , ET_REL ));
410 D(bug("[ELF2HUNK] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA] , AROS_ELF_DATA ));
411 D(bug("[ELF2HUNK] machine is %d - should be %d\n", eh->machine , AROS_ELF_MACHINE));
413 set_error(ENOEXEC);
414 return 0;
417 return 1;
420 struct hunkheader {
421 ULONG type;
422 ULONG size; /* Size in ULONGs */
423 void *data;
424 ULONG relocs;
425 int hunk; /* Allocatable hunk ID */
426 struct hunkreloc {
427 ULONG shid; /* ELF hunk base to add to... */
428 ULONG offset; /* offset in this hunk. */
429 const char *symbol;
430 } *reloc;
433 static int relocate
435 struct elfheader *eh,
436 struct sheader *sh,
437 ULONG shrel_idx,
438 int symtab_shndx,
439 struct relo *rel,
440 struct hunkheader **hh
443 struct sheader *shrel = &sh[shrel_idx];
444 struct sheader *shsymtab = &sh[SHINDEX(shrel->link)];
445 struct sheader *toreloc = &sh[SHINDEX(shrel->info)];
447 struct symbol *symtab = (struct symbol *)hh[SHINDEX(shrel->link)]->data;
448 struct hunkheader *h = hh[SHINDEX(shrel->info)];
451 * Ignore relocs if the target section has no allocation. that can happen
452 * eg. with a .debug PROGBITS and a .rel.debug section
454 D(bug("[ELF2HUNK] sh[%d].flags = 0x%x\n", (int)SHINDEX(shrel->info), (int)toreloc->flags));
455 if (!(toreloc->flags & SHF_ALLOC))
456 return 1;
458 ULONG numrel = shrel->size / shrel->entsize;
459 ULONG i;
460 ULONG hrels;
462 hrels = h->relocs;
463 h->relocs += numrel;
464 h->reloc = realloc(h->reloc, h->relocs * sizeof(struct hunkreloc));
465 struct hunkreloc *hrel = &h->reloc[hrels];
467 struct symbol *SysBase_sym = NULL;
469 for (i=0; i<numrel; i++, rel++)
471 struct symbol sym;
472 ULONG offset;
473 ULONG shindex;
474 ULONG hunk;
475 ULONG value;
476 const char *symname;
478 rel_fixup(rel);
480 #ifdef __arm__
482 * R_ARM_V4BX are actually special marks for the linker.
483 * They even never have a target (shindex == SHN_UNDEF),
484 * so we simply ignore them before doing any checks.
486 if (ELF_R_TYPE(rel->info) == R_ARM_V4BX)
487 continue;
488 #endif
490 sym = symtab[ELF_R_SYM(rel->info)];
491 sym_fixup(&sym);
492 offset = rel->offset;
493 symname = (const char *)(hh[SHINDEX(shsymtab->link)]->data + sym.name);
495 if (sym.shindex != SHN_XINDEX)
496 shindex = sym.shindex;
498 else {
499 if (symtab_shndx < 0) {
500 D(bug("[ELF2HUNK] got symbol with shndx 0xfff, but there's no symtab shndx table\n"));
501 set_error(EINVAL);
502 return 0;
504 shindex = ntohl(((ULONG *)hh[symtab_shndx]->data)[ELF_R_SYM(rel->info)]);
507 D(bug("[ELF2HUNK] Processing %d symbol %s\n", (int)shindex, symname));
509 switch (shindex)
512 case SHN_UNDEF:
513 D(bug("[ELF2HUNK] Undefined symbol '%s'\n", symname));
514 set_error(EINVAL);
515 return 0;
517 case SHN_COMMON:
518 D(bug("[ELF2HUNK] COMMON symbol '%s'\n", symname));
519 set_error(EINVAL);
521 return 0;
523 case SHN_ABS:
524 if (SysBase_sym == NULL)
526 if (strncmp(symname, "SysBase", 8) == 0)
527 goto SysBase_yes;
528 else
529 goto SysBase_no;
531 else
532 if (SysBase_sym == &sym)
534 SysBase_yes: hunk = ~0; value = SysBase;
536 else {
537 SysBase_no: hunk = ~0; value = sym.value;
539 break;
541 default:
542 hunk = SHINDEX(shindex);
543 value = sym.value;
544 break;
547 switch (ELF_R_TYPE(rel->info))
549 case R_68K_32:
550 value += rel->addend;
551 break;
553 case R_68K_PC32:
554 value += rel->addend - offset;
555 break;
557 case R_68K_PC16:
558 bug("[ELF2HUNK] Unsupported relocation type R_68K_PC16\n");
559 set_error(EINVAL);
560 break;
562 case R_68k_NONE:
563 break;
565 default:
566 bug("[ELF2HUNK] Unrecognized relocation type %d %d\n", (int)i, (int)ELF_R_TYPE(rel->info));
567 set_error(EINVAL);
568 return 0;
571 D(bug("[ELF2HUNK] Hunk %d, offset 0x%x: base 0x%x\n", (int)hunk, (int)offset, (int)value));
572 *(ULONG *)(h->data + offset) = htonl(value + ntohl(*(ULONG *)(h->data + offset)));
573 if (hunk == ~0) {
574 h->relocs--;
575 continue;
577 hrel->shid = hunk;
578 hrel->offset = offset;
579 hrel->symbol = symname;
580 hrel++;
583 return 1;
586 int reloc_cmp(const void *a, const void *b)
588 const struct hunkreloc *ha = a, *hb = b;
590 if (ha->shid != hb->shid)
591 return hb->shid - ha->shid;
592 return hb->offset - ha->offset;
595 static int wlong(int fd, ULONG val)
597 val = htonl(val);
598 return write(fd, &val, sizeof(val));
601 int sym_dump(int hunk_fd, struct sheader *sh, struct hunkheader **hh, int shid, int symtabndx)
603 int i, err, syms;
604 struct symbol *sym = hh[symtabndx]->data;
605 struct sheader *symtab = &sh[SHINDEX(symtabndx)];
607 syms = symtab->size / sizeof(struct symbol);
609 if (syms == 0)
610 return 1;
612 wlong(hunk_fd, HUNK_SYMBOL);
613 wlong(hunk_fd, syms);
615 /* Dump symbols for this hunk */
616 for (i = 0; i < syms ; i++) {
617 struct symbol s;
618 const char *name;
619 int lsize;
621 s = sym[i];
622 sym_fixup(&s);
624 if (SHINDEX(s.shindex) != shid)
625 continue;
627 name = (const char *)(hh[SHINDEX(symtab->link)]->data + s.name);
628 D(bug("\t0x%08x: %s\n", (int)s.value, name));
629 lsize = (strlen(name) + 4) / 4;
630 wlong(hunk_fd, lsize);
631 err = write(hunk_fd, name, lsize * 4);
632 if (err < 0)
633 return 0;
634 wlong(hunk_fd, s.value);
636 wlong(hunk_fd, 0);
638 return 1;
641 static void reloc_dump(int hunk_fd, struct hunkheader **hh, int h)
643 int i;
645 if (hh[h]->relocs == 0)
646 return;
648 /* Sort the relocations by reference hunk id */
649 qsort(hh[h]->reloc, hh[h]->relocs, sizeof(hh[h]->reloc[0]), reloc_cmp);
651 wlong(hunk_fd, HUNK_RELOC32);
652 D(bug("\tHUNK_RELOC32: %d relocations\n", (int)hh[h]->relocs));
654 for (i = 0; i < hh[h]->relocs; ) {
655 int count;
656 int shid = hh[h]->reloc[i].shid;
657 for (count = i; count < hh[h]->relocs; count++)
658 if (hh[h]->reloc[count].shid != shid)
659 break;
660 count -= i;
661 wlong(hunk_fd, count);
662 D(bug("\t %d relocations relative to Hunk %d\n", count, hh[shid]->hunk));
663 /* Convert from ELF hunk ID to AOS hunk ID */
664 wlong(hunk_fd, hh[shid]->hunk);
665 for (; count > 0; i++, count--) {
666 D(bug("\t\t%d: 0x%08x %s\n", i, (int)hh[h]->reloc[i].offset, hh[h]->reloc[i].symbol));
667 wlong(hunk_fd, hh[h]->reloc[i].offset);
670 wlong(hunk_fd, 0);
673 static int copy_to(int in, int out)
675 static char buff[64*1024];
676 int len, err = 0;
678 do {
679 len = read(in, buff, sizeof(buff));
680 if (len < 0) {
681 perror("Can't read from input file\n");
682 err = len;
684 if (len == 0)
685 break;
686 } while ((err = write(out, buff, len)) == len);
688 if (err < 0) {
689 perror("Can't write to output file\n");
690 return -errno;
693 return 0;
696 int elf2hunk(int file, int hunk_fd, const char *libname, int flags)
698 struct hunkheader **hh;
699 struct elfheader eh;
700 struct sheader *sh;
701 int symtab_shndx = -1;
702 int err;
703 ULONG i;
704 BOOL exec_hunk_seen = FALSE;
705 ULONG int_shnum;
706 int hunks = 0;
708 /* load and validate ELF header */
709 D(bug("Load header\n"));
710 if ((flags & F_NOCONVERT) || !load_header(file, &eh)) {
711 /* If it's not an ELF, just copy it.
713 * This simplifies a number of mmakefiles
714 * for the m68k-amiga boot and ISO creation
716 lseek(file, 0, SEEK_SET);
717 return (copy_to(file, hunk_fd) == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
720 D(bug("Read SHNum\n"));
721 int_shnum = read_shnum(file, &eh);
722 if (!int_shnum)
723 return EXIT_FAILURE;
725 /* load section headers */
726 D(bug("Load Section Headers @0x%08x\n", (int)eh.shoff));
727 if (!(sh = load_block(file, eh.shoff, int_shnum * eh.shentsize)))
728 return EXIT_FAILURE;
730 sh_fixup(sh, int_shnum);
732 /* Looks like we have a valid executable. Generate a
733 * HUNK header set. Not all may be filled in.
735 hh = calloc(sizeof(*hh), int_shnum);
737 /* Iterate over the section headers in order to do some stuff... */
738 D(bug("Look for symbol tables\n"));
739 for (i = 0; i < int_shnum; i++)
742 Load the symbol and string table(s).
744 NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states
745 that only one symbol table per file is allowed. However, it
746 also states that this may change in future... we already handle it.
748 D(bug("sh[%d].type = 0x%08x, .offset = 0x%08x, .size = 0x%08x\n",
749 (int)i, (int)sh[i].type, (int)sh[i].offset, (int)sh[i].size));
750 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB || sh[i].type == SHT_SYMTAB_SHNDX)
752 hh[i] = calloc(sizeof(struct hunkheader), 1);
753 hh[i]->type = (sh[i].type == SHT_SYMTAB) ? HUNK_SYMBOL : 0;
754 hh[i]->hunk = -1;
755 hh[i]->data = load_block(file, sh[i].offset, sh[i].size);
756 if (!hh[i]->data)
757 goto error;
759 if (sh[i].type == SHT_SYMTAB_SHNDX) {
760 if (symtab_shndx == -1)
761 symtab_shndx = i;
762 else
763 D(bug("[ELF2HUNK] file contains multiple symtab shndx tables. only using the first one\n"));
766 else
767 /* Load the section in memory if needed, and make an hunk out of it */
768 if (sh[i].flags & SHF_ALLOC && sh[i].size > 0)
770 hh[i] = calloc(sizeof(struct hunkheader), 1);
771 hh[i]->size = sh[i].size;
772 hh[i]->hunk = hunks++;
774 if (sh[i].type == SHT_NOBITS) {
775 /* BSS area */
776 hh[i]->type = HUNK_BSS;
777 hh[i]->data = NULL;
778 } else {
779 if (sh[i].flags & SHF_EXECINSTR) {
780 hh[i]->type = HUNK_CODE;
781 exec_hunk_seen = TRUE;
782 } else {
783 hh[i]->type = HUNK_DATA;
785 hh[i]->data = load_block(file, sh[i].offset, sh[i].size);
790 /* Relocate the sections */
791 D(bug("Convert relocation tables\n"));
792 for (i = 0; i < int_shnum; i++)
794 /* Does this relocation section refer to a hunk? If so, addr must be != 0 */
795 if ((sh[i].type == AROS_ELF_REL)
796 && hh[SHINDEX(sh[i].info)]
797 && hh[SHINDEX(sh[i].info)]->data)
799 void *reloc = load_block(file, sh[i].offset, sh[i].size);
801 relocate(&eh, sh, i, symtab_shndx, reloc, hh);
803 free(reloc);
807 D(bug("HUNK_HEADER: \"%s\", hunks=%d, first=%d, last=%d\n", libname, hunks, 0, hunks-1));
809 wlong(hunk_fd, HUNK_HEADER);
810 if (libname == NULL) {
811 wlong(hunk_fd, 0); /* No name */
812 } else {
813 int lsize = (strlen(libname) + 4) / 4;
814 wlong(hunk_fd, lsize);
815 err = write(hunk_fd, libname, lsize * 4);
816 if (err < 0)
817 return EXIT_FAILURE;
819 wlong(hunk_fd, hunks);
820 wlong(hunk_fd, 0); /* First hunk is #0 */
821 wlong(hunk_fd, hunks - 1); /* Last hunk is hunks-1 */
823 /* Write all allocatable hunk sizes */
824 for (i = 0; i < int_shnum; i++) {
825 const __attribute__((unused)) char *names[3]={ "CODE", "DATA", "BSS" };
826 if (hh[i]==NULL || hh[i]->hunk < 0)
827 continue;
829 D(bug("\tHunk #%d, %s, lsize=%d\n", hh[i]->hunk, names[hh[i]->type - HUNK_CODE], (int)(hh[i]->size+4)/4));
830 wlong(hunk_fd, (hh[i]->size + 4) / 4);
833 /* Write all hunks */
834 for (i = hunks = 0; i < int_shnum; i++) {
835 int s;
837 if (hh[i]==NULL || hh[i]->hunk < 0)
838 continue;
840 switch (hh[i]->type) {
841 case HUNK_BSS:
842 D(bug("HUNK_BSS: %d longs\n", (int)((hh[i]->size + 4) / 4)));
843 wlong(hunk_fd, hh[i]->type);
844 wlong(hunk_fd, (hh[i]->size + 4) / 4);
845 if (0) {
846 for (s = 0; s < int_shnum; s++) {
847 if (hh[s] && hh[s]->type == HUNK_SYMBOL)
848 sym_dump(hunk_fd, sh, hh, i, s);
851 wlong(hunk_fd, HUNK_END);
852 hunks++;
853 break;
854 case HUNK_CODE:
855 case HUNK_DATA:
856 D(bug("#%d HUNK_%s: %d longs\n", hh[i]->hunk, hh[i]->type == HUNK_CODE ? "CODE" : "DATA", (int)((hh[i]->size + 4) / 4)));
857 wlong(hunk_fd, hh[i]->type);
858 wlong(hunk_fd, (hh[i]->size + 4)/4);
859 err = write(hunk_fd, hh[i]->data, ((hh[i]->size + 4)/4)*4);
860 if (err < 0)
861 return EXIT_FAILURE;
862 if (0) {
863 for (s = 0; s < int_shnum; s++) {
864 if (hh[s] && hh[s]->type == HUNK_SYMBOL)
865 sym_dump(hunk_fd, sh, hh, i, s);
868 reloc_dump(hunk_fd, hh, i);
869 wlong(hunk_fd, HUNK_END);
870 D(bug("\tHUNK_END\n"));
871 break;
872 default:
873 D(bug("Unsupported allocatable hunk type %d\n", (int)hh[i]->type));
874 return EXIT_FAILURE;
878 /* Free all blocks */
879 for (i = 0; i < int_shnum; i++) {
880 if (hh[i]) {
881 if (hh[i]->data)
882 free(hh[i]->data);
883 if (hh[i]->reloc)
884 free(hh[i]->reloc);
885 free(hh[i]);
888 free(hh);
889 free(sh);
891 D(bug("All good, all done.\n"));
892 return EXIT_SUCCESS;
894 error:
895 return EXIT_FAILURE;
898 static int copy(const char *src, const char *dst, int flags);
900 static int copy_dir(const char *src, const char *dst, int flags)
902 DIR *sdir;
903 struct dirent *de;
904 char spath[PATH_MAX], dpath[PATH_MAX];
905 char *sp, *dp;
906 int sleft, dleft;
907 int err = EXIT_SUCCESS;
909 sdir = opendir(src);
910 if (sdir == NULL) {
911 perror(src);
912 return EXIT_FAILURE;
915 snprintf(spath, sizeof(spath), "%s/", src);
916 spath[sizeof(spath)-1] = 0;
917 sp = &spath[strlen(spath)];
918 sleft = &spath[sizeof(spath)-1] - sp;
920 snprintf(dpath, sizeof(dpath), "%s/", dst);
921 dpath[sizeof(dpath)-1] = 0;
922 dp = &dpath[strlen(dpath)];
923 dleft = &dpath[sizeof(dpath)-1] - dp;
925 while ((de = readdir(sdir)) != NULL) {
926 int eflags = 0;
928 if ((strcmp(de->d_name, ".") == 0) ||
929 (strcmp(de->d_name, "..") == 0))
930 continue;
932 /* Don't convert anything in a Development directory */
933 if (strcasecmp(de->d_name, "Development") == 0)
934 eflags |= F_NOCONVERT;
936 strncpy(sp, de->d_name, sleft);
937 sp[sleft-1] = 0;
938 strncpy(dp, de->d_name, dleft);
939 dp[dleft-1] = 0;
940 err = copy(spath, dpath, flags | eflags);
941 if (err != EXIT_SUCCESS)
942 break;
945 closedir(sdir);
947 return err;
950 static int copy(const char *src, const char *dst, int flags)
952 int src_fd, hunk_fd;
953 struct stat st;
954 int mode, ret;
956 if (flags & F_VERBOSE)
957 printf("%s ->\n %s\n", src, dst);
959 if (stat(src, &st) >= 0) {
960 mode = st.st_mode;
961 } else {
962 mode = 0755;
965 if (S_ISDIR(mode)) {
966 unlink(dst);
967 mkdir(dst, mode);
968 return copy_dir(src, dst, flags);
971 src_fd = open(src, O_RDONLY);
972 if (src_fd < 0) {
973 perror(src);
974 return EXIT_FAILURE;
977 hunk_fd = open(dst, O_RDWR | O_CREAT | O_TRUNC, mode);
978 if (hunk_fd < 0) {
979 perror(dst);
980 return EXIT_FAILURE;
983 ret = elf2hunk(src_fd, hunk_fd, NULL, flags);
984 if (ret != 0)
985 perror(src);
987 close(src_fd);
988 close(hunk_fd);
990 return ret;
993 int main(int argc, char **argv)
995 int flags = 0;
997 if (argc == 4 && strcmp(argv[1],"-v") == 0) {
998 flags |= F_VERBOSE;
999 argc--;
1000 argv++;
1003 if (argc != 3) {
1004 fprintf(stderr, "Usage:\n%s file.elf file.hunk\n", argv[0]);
1005 fprintf(stderr, "%s src-dir dest-dir\n", argv[0]);
1006 return EXIT_FAILURE;
1009 return copy(argv[1], argv[2], flags);