refactored some code. compiles now without suppresing any warning with gcc-6.3.0.
[AROS.git] / tools / elf2hunk / elf2hunk.c
blob6ee2942c7d7c4ba9db4624e9679c2016466ee421
1 /*
2 Copyright © 1995-2017, 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 #if !defined(FALSE)&&!defined(TRUE)
42 #define FALSE 0
43 #define TRUE (!FALSE)
44 #endif
46 /* Memory allocation flags */
47 #define MEMF_ANY 0L
48 #define MEMF_PUBLIC (1L<<0)
49 #define MEMF_CHIP (1L<<1)
50 #define MEMF_FAST (1L<<2)
51 #define MEMF_EXECUTABLE (1L<<4) /* AmigaOS v4 compatible */
52 #define MEMF_LOCAL (1L<<8)
53 #define MEMF_24BITDMA (1L<<9)
54 #define MEMF_KICK (1L<<10)
55 #define MEMF_31BIT (1L<<12) /* Low address space (<2GB). Effective only on 64 bit machines. */
56 #define MEMF_CLEAR (1L<<16) /* Explicitly clear memory after allocation */
57 #define MEMF_LARGEST (1L<<17)
58 #define MEMF_REVERSE (1L<<18)
59 #define MEMF_TOTAL (1L<<19)
60 #define MEMF_HWALIGNED (1L<<20) /* For AllocMem() - align address and size to physical page boundary */
61 #define MEMF_SEM_PROTECTED (1L<<20) /* For CreatePool() - add semaphore protection to the pool */
62 #define MEMF_NO_EXPUNGE (1L<<31)
64 #define HUNKF_ADVISORY (1L<<29)
65 #define HUNKF_CHIP (1L<<30)
66 #define HUNKF_FAST (1L<<31)
67 #define HUNKF_MEMFLAGS (HUNKF_CHIP | HUNKF_FAST)
70 #define HUNK_CODE 1001
71 #define HUNK_DATA 1002
72 #define HUNK_BSS 1003
73 #define HUNK_RELOC32 1004
74 #define HUNK_SYMBOL 1008
75 #define HUNK_END 1010
76 #define HUNK_HEADER 1011
78 #define SHT_PROGBITS 1
79 #define SHT_SYMTAB 2
80 #define SHT_STRTAB 3
81 #define SHT_RELA 4
82 #define SHT_NOBITS 8
83 #define SHT_REL 9
84 #define SHT_SYMTAB_SHNDX 18
86 #define ET_REL 1
87 #define ET_EXEC 2
89 #define EM_386 3
90 #define EM_68K 4
91 #define EM_PPC 20
92 #define EM_ARM 40
93 #define EM_X86_64 62 /* AMD x86-64 */
95 #define R_386_NONE 0
96 #define R_386_32 1
97 #define R_386_PC32 2
99 /* AMD x86-64 relocations. */
100 #define R_X86_64_NONE 0 /* No reloc */
101 #define R_X86_64_64 1 /* Direct 64 bit */
102 #define R_X86_64_PC32 2 /* PC relative 32 bit signed */
103 #define R_X86_64_32 10
104 #define R_X86_64_32S 11
106 #define R_68k_NONE 0
107 #define R_68K_32 1
108 #define R_68K_PC32 4
109 #define R_68K_PC16 5
111 #define R_PPC_NONE 0
112 #define R_PPC_ADDR32 1
113 #define R_PPC_ADDR16_LO 4
114 #define R_PPC_ADDR16_HA 6
115 #define R_PPC_REL24 10
116 #define R_PPC_REL32 26
117 #define R_PPC_REL16_LO 250
118 #define R_PPC_REL16_HA 252
120 #define R_ARM_NONE 0
121 #define R_ARM_PC24 1
122 #define R_ARM_ABS32 2
123 #define R_ARM_CALL 28
124 #define R_ARM_JUMP24 29
125 #define R_ARM_V4BX 40
126 #define R_ARM_PREL31 42
127 #define R_ARM_MOVW_ABS_NC 43
128 #define R_ARM_MOVT_ABS 44
130 #define STT_NOTYPE 0
131 #define STT_OBJECT 1
132 #define STT_FUNC 2
133 #define STT_SECTION 3
134 #define STT_FILE 4
135 #define STT_LOPROC 13
136 #define STT_HIPROC 15
138 #define SHN_UNDEF 0
139 #define SHN_LORESERVE 0xff00
140 #define SHN_ABS 0xfff1
141 #define SHN_COMMON 0xfff2
142 #define SHN_XINDEX 0xffff
143 #define SHN_HIRESERVE 0xffff
145 #define SHF_WRITE (1 << 0)
146 #define SHF_ALLOC (1 << 1)
147 #define SHF_EXECINSTR (1 << 2)
149 #define ELF_ST_TYPE(i) ((i) & 0x0F)
151 #define EI_VERSION 6
152 #define EV_CURRENT 1
154 #define EI_DATA 5
155 #define ELFDATA2LSB 1
156 #define ELFDATA2MSB 2
158 #define EI_CLASS 4
159 #define ELFCLASS32 1
160 #define ELFCLASS64 2 /* 64-bit objects */
162 #define EI_OSABI 7
163 #define EI_ABIVERSION 8
165 #define ELFOSABI_AROS 15
167 #define PF_X (1 << 0)
169 struct elfheader
171 UBYTE ident[16];
172 UWORD type;
173 UWORD machine;
174 ULONG version;
175 IPTR entry;
176 IPTR phoff;
177 IPTR shoff;
178 ULONG flags;
179 UWORD ehsize;
180 UWORD phentsize;
181 UWORD phnum;
182 UWORD shentsize;
183 UWORD shnum;
184 UWORD shstrndx;
185 } __attribute__((packed));
187 struct sheader
189 ULONG name;
190 ULONG type;
191 IPTR flags;
192 IPTR addr;
193 IPTR offset;
194 IPTR size;
195 ULONG link;
196 ULONG info;
197 IPTR addralign;
198 IPTR entsize;
199 } __attribute__((packed));
201 #define PT_LOAD 1
203 struct pheader
205 ULONG type;
206 ULONG offset;
207 IPTR vaddr;
208 IPTR paddr;
209 ULONG filesz;
210 ULONG memsz;
211 ULONG flags;
212 ULONG align;
213 } __attribute__((packed));
215 struct symbol
217 ULONG name; /* Offset of the name string in the string table */
218 IPTR value; /* Varies; eg. the offset of the symbol in its hunk */
219 IPTR size; /* How much memory does the symbol occupy */
220 UBYTE info; /* What kind of symbol is this ? (global, variable, etc) */
221 UBYTE other; /* undefined */
222 UWORD shindex; /* In which section is the symbol defined ? */
223 } __attribute__((packed));
225 #define ELF_R_SYM(val) ((val) >> 8)
226 #define ELF_R_TYPE(val) ((val) & 0xff)
227 #define ELF_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
229 struct relo
231 IPTR offset; /* Address of the relocation relative to the section it refers to */
232 IPTR info; /* Type of the relocation */
233 SIPTR addend; /* Constant addend used to compute value */
236 /* Note: the conversion below is not in line with ELF specification and is fixed in GNU binutils since 2008
237 * See: https://sourceware.org/bugzilla/show_bug.cgi?id=5900
239 /* convert section header number to array index */
240 /*#define SHINDEX(n) \
241 ((n) < SHN_LORESERVE ? (n) : ((n) <= SHN_HIRESERVE ? 0 : (n) - (SHN_HIRESERVE + 1 - SHN_LORESERVE)))*/
243 /* convert section header array index to section number */
244 /*#define SHNUM(i) \
245 ((i) < SHN_LORESERVE ? (i) : (i) + (SHN_HIRESERVE + 1 - SHN_LORESERVE))*/
247 /* m68k Machine's native values */
248 #define AROS_ELF_CLASS ELFCLASS32
249 #define AROS_ELF_DATA ELFDATA2MSB
250 #define AROS_ELF_MACHINE EM_68K
251 #define AROS_ELF_REL SHT_RELA
254 #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
255 # include <stdarg.h>
256 # define VA_START(args, lastarg) va_start(args, lastarg)
257 #else
258 # include <varargs.h>
259 # define VA_START(args, lastarg) va_start(args)
260 #endif
262 #ifdef PROTOTYPES
263 # define PARAMS(x) x
264 #else
265 # define PARAMS(x) ()
266 #endif /* PROTOTYPES */
268 static void set_error(int err)
270 errno = err;
273 #if defined(DEBUG) && DEBUG
274 #define D(x) x
275 #define DB2(x) x
276 #else
277 #define D(x)
278 #define DB2(x)
279 #endif
280 #define bug(fmt,args...) fprintf(stderr, fmt ,##args )
282 static int must_swap = -1;
284 static void eh_fixup(struct elfheader *eh)
286 /* Endian swaps */
287 if (eh->type == 256) {
288 must_swap = 1;
289 eh->type = ntohs(eh->type);
290 eh->machine = ntohs(eh->machine);
291 eh->version = ntohl(eh->version);
292 eh->entry = ntohl(eh->entry);
293 eh->phoff = ntohl(eh->phoff);
294 eh->shoff = ntohl(eh->shoff);
295 eh->flags = ntohl(eh->flags);
296 eh->ehsize = ntohs(eh->ehsize);
297 eh->phentsize = ntohs(eh->phentsize);
298 eh->phnum = ntohs(eh->phnum);
299 eh->shentsize = ntohs(eh->shentsize);
300 eh->shnum = ntohs(eh->shnum);
301 eh->shstrndx = ntohs(eh->shstrndx);
302 } else {
303 must_swap = 0;
307 static void sh_fixup(struct sheader *sh, int n)
309 if (must_swap == 0)
310 return;
312 for (; n > 0; n--, sh++) {
313 sh->name = ntohl(sh->name);
314 sh->type = ntohl(sh->type);
315 sh->flags = ntohl(sh->flags);
316 sh->addr = ntohl(sh->addr);
317 sh->offset = ntohl(sh->offset);
318 sh->size = ntohl(sh->size);
319 sh->link = ntohl(sh->link);
320 sh->info = ntohl(sh->info);
321 sh->addralign = ntohl(sh->addralign);
322 sh->entsize = ntohl(sh->entsize);
326 static void rel_fixup(struct relo *rel)
328 if (must_swap == 0)
329 return;
331 rel->offset = ntohl(rel->offset);
332 rel->info = ntohl(rel->info);
333 rel->addend = ntohl(rel->addend);
336 void sym_fixup(struct symbol *sym)
338 if (must_swap == 0)
339 return;
341 sym->name = ntohl(sym->name);
342 sym->value = ntohl(sym->value);
343 sym->size = ntohl(sym->size);
344 sym->shindex = ntohs(sym->shindex);
347 static void *load_block (int file,ULONG offset,ULONG size)
349 ULONG lsize = (size + sizeof(ULONG) - 1) / sizeof(ULONG);
350 D(bug("[ELF2HUNK] Load Block\n"));
351 D(bug("[ELF2HUNK] (size=%d)\n",(int)size));
352 void *block = malloc(lsize * sizeof(ULONG));
353 if (block) {
354 lseek(file, offset, SEEK_SET);
355 if (read(file, block, size) == size) {
356 return block;
359 free(block);
360 set_error(EIO);
361 } else
362 set_error(ENOMEM);
364 return NULL;
367 static ULONG read_shnum(int file, struct elfheader *eh)
369 ULONG shnum = eh->shnum;
371 /* the ELF header only uses 16 bits to store the count of section headers,
372 * so it can't handle more than 65535 headers. if the count is 0, and an
373 * offset is defined, then the real count can be found in the first
374 * section header (which always exists).
376 * similarly, if the string table index is SHN_XINDEX, then the actual
377 * index is found in the first section header also.
379 * see the System V ABI 2001-04-24 draft for more details.
381 if (eh->shnum == 0)
383 struct sheader sh;
385 if (eh->shoff == 0) {
386 set_error(ENOEXEC);
387 return 0;
390 lseek(file, eh->shoff, SEEK_SET);
391 if (read(file, &sh, sizeof(sh)) != sizeof(sh))
392 return 0;
394 sh_fixup(&sh, 1);
396 /* wider section header count is in the size field */
397 shnum = sh.size;
399 /* sanity, if they're still invalid then this isn't elf */
400 if (shnum == 0)
401 set_error(ENOEXEC);
404 return shnum;
407 static int load_header(int file, struct elfheader *eh)
409 lseek(file, 0, SEEK_SET);
410 if (read(file, eh, sizeof(struct elfheader)) != sizeof(struct elfheader)) {
411 D(bug("[ELF2HUNK] Can't read the %d byte ELF header\n", (int)sizeof(struct elfheader)));
412 return 0;
415 eh_fixup(eh);
417 if (eh->ident[0] != 0x7f || eh->ident[1] != 'E' ||
418 eh->ident[2] != 'L' || eh->ident[3] != 'F') {
419 D(bug("[ELF2HUNK] Not an ELF object\n"));
420 return 0;
422 D(bug("[ELF2HUNK] ELF object\n"));
424 /* WANT_CLASS should be defined for your target */
425 if (eh->ident[EI_CLASS] != AROS_ELF_CLASS ||
426 eh->ident[EI_VERSION] != EV_CURRENT ||
427 eh->type != ET_REL ||
428 eh->ident[EI_DATA] != AROS_ELF_DATA ||
429 eh->machine != AROS_ELF_MACHINE)
431 D(bug("[ELF2HUNK] Object is of wrong type\n"));
432 D(bug("[ELF2HUNK] EI_CLASS is %d - should be %d\n", eh->ident[EI_CLASS] , AROS_ELF_CLASS ));
433 D(bug("[ELF2HUNK] EI_VERSION is %d - should be %d\n", eh->ident[EI_VERSION], EV_CURRENT ));
434 D(bug("[ELF2HUNK] type is %d - should be %d\n", eh->type , ET_REL ));
435 D(bug("[ELF2HUNK] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA] , AROS_ELF_DATA ));
436 D(bug("[ELF2HUNK] machine is %d - should be %d\n", eh->machine , AROS_ELF_MACHINE));
438 set_error(ENOEXEC);
439 return 0;
442 return 1;
445 struct hunkheader {
446 ULONG type;
447 ULONG memflags; /* Memory flags */
448 ULONG size; /* Size in ULONGs */
449 void *data;
450 ULONG relocs;
451 int hunk; /* Allocatable hunk ID */
452 struct hunkreloc {
453 ULONG shid; /* ELF hunk base to add to... */
454 ULONG offset; /* offset in this hunk. */
455 const char *symbol;
456 } *reloc;
459 static int relocate
461 struct elfheader *eh,
462 struct sheader *sh,
463 ULONG shrel_idx,
464 int symtab_shndx,
465 struct relo *rel,
466 struct hunkheader **hh
469 struct sheader *shrel = &sh[shrel_idx];
470 struct sheader *shsymtab = &sh[shrel->link];
471 struct sheader *toreloc = &sh[shrel->info];
473 struct symbol *symtab = (struct symbol *)hh[shrel->link]->data;
474 struct hunkheader *h = hh[shrel->info];
477 * Ignore relocs if the target section has no allocation. that can happen
478 * eg. with a .debug PROGBITS and a .rel.debug section
480 D(bug("[ELF2HUNK] sh[%d].flags = 0x%x\n", (int)(shrel->info), (int)toreloc->flags));
481 if (!(toreloc->flags & SHF_ALLOC))
482 return 1;
484 ULONG numrel = shrel->size / shrel->entsize;
485 ULONG i;
486 ULONG hrels;
488 hrels = h->relocs;
489 h->relocs += numrel;
490 h->reloc = realloc(h->reloc, h->relocs * sizeof(struct hunkreloc));
491 struct hunkreloc *hrel = &h->reloc[hrels];
493 for (i=0; i<numrel; i++, rel++)
495 struct symbol sym;
496 ULONG offset;
497 ULONG shindex;
498 ULONG shid = 0;
499 ULONG value = 0;
500 const char *symname;
502 rel_fixup(rel);
504 #ifdef __arm__
506 * R_ARM_V4BX are actually special marks for the linker.
507 * They even never have a target (shindex == SHN_UNDEF),
508 * so we simply ignore them before doing any checks.
510 if (ELF_R_TYPE(rel->info) == R_ARM_V4BX)
511 continue;
512 #endif
514 sym = symtab[ELF_R_SYM(rel->info)];
515 sym_fixup(&sym);
516 offset = rel->offset;
517 symname = (const char *)(hh[shsymtab->link]->data + sym.name);
519 if (sym.shindex != SHN_XINDEX)
520 shindex = sym.shindex;
522 else {
523 if (symtab_shndx < 0) {
524 bug("[ELF2HUNK] got symbol with shndx 0xfff, but there's no symtab shndx table\n");
525 set_error(EINVAL);
526 return 0;
528 shindex = ntohl(((ULONG *)hh[symtab_shndx]->data)[ELF_R_SYM(rel->info)]);
531 D(bug("[ELF2HUNK] Processing %d symbol %s\n", (int)shindex, symname));
533 switch (shindex)
536 case SHN_UNDEF:
537 if (ELF_R_TYPE(rel->info) != 0) {
538 bug("[ELF2HUNK] SHN_UNDEF symbol '%s', type %d unsupported\n", symname, (int)ELF_R_TYPE(rel->info));
539 set_error(EINVAL);
540 return 0;
542 break;
544 case SHN_COMMON:
545 bug("[ELF2HUNK] SHN_COMMON symbol '%s' unsupported\n", symname);
546 set_error(EINVAL);
548 return 0;
550 case SHN_ABS:
551 shid = ~0; value = sym.value;
552 break;
554 default:
555 shid = shindex;
556 value = sym.value;
557 break;
560 switch (ELF_R_TYPE(rel->info))
562 case R_68K_32:
563 value += rel->addend;
564 break;
566 case R_68K_PC32:
567 value += rel->addend - offset;
568 break;
570 case R_68K_PC16:
571 bug("[ELF2HUNK] Unsupported relocation type R_68K_PC16\n");
572 set_error(EINVAL);
573 return 0;
574 break;
576 case R_68k_NONE:
577 shid = ~0;
578 break;
580 default:
581 bug("[ELF2HUNK] Unrecognized relocation type %d %d\n", (int)i, (int)ELF_R_TYPE(rel->info));
582 set_error(EINVAL);
583 return 0;
586 D(bug("[ELF2HUNK] shid %d, offset 0x%x: base 0x%x\n", (int)shid, (int)offset, (int)value));
587 *(ULONG *)(h->data + offset) = htonl(value + ntohl(*(ULONG *)(h->data + offset)));
588 if (shid == ~0) {
589 h->relocs--;
590 continue;
592 hrel->shid = shid;
593 hrel->offset = offset;
594 hrel->symbol = symname;
595 hrel++;
598 return 1;
601 int reloc_cmp(const void *a, const void *b)
603 const struct hunkreloc *ha = a, *hb = b;
605 if (ha->shid != hb->shid)
606 return hb->shid - ha->shid;
607 return hb->offset - ha->offset;
610 static int wlong(int fd, ULONG val)
612 val = htonl(val);
613 return write(fd, &val, sizeof(val));
616 int sym_dump(int hunk_fd, struct sheader *sh, struct hunkheader **hh, int shid, int symtabndx)
618 int i, err, syms;
619 struct symbol *sym = hh[symtabndx]->data;
620 struct sheader *symtab = &sh[symtabndx];
622 syms = symtab->size / sizeof(struct symbol);
624 if (syms == 0)
625 return 1;
627 wlong(hunk_fd, HUNK_SYMBOL);
628 wlong(hunk_fd, syms);
630 /* Dump symbols for this hunk */
631 for (i = 0; i < syms ; i++) {
632 struct symbol s;
633 const char *name;
634 int lsize;
636 s = sym[i];
637 sym_fixup(&s);
639 if (s.shindex != shid)
640 continue;
642 name = (const char *)(hh[symtab->link]->data + s.name);
643 D(bug("\t0x%08x: %s\n", (int)s.value, name));
644 lsize = (strlen(name) + 4) / 4;
645 wlong(hunk_fd, lsize);
646 err = write(hunk_fd, name, lsize * 4);
647 if (err < 0)
648 return 0;
649 wlong(hunk_fd, s.value);
651 wlong(hunk_fd, 0);
653 return 1;
656 static void reloc_dump(int hunk_fd, struct hunkheader **hh, int h)
658 int i;
660 if (hh[h]->relocs == 0)
661 return;
663 /* Sort the relocations by reference hunk id */
664 qsort(hh[h]->reloc, hh[h]->relocs, sizeof(hh[h]->reloc[0]), reloc_cmp);
666 wlong(hunk_fd, HUNK_RELOC32);
667 D(bug("\tHUNK_RELOC32: %d relocations\n", (int)hh[h]->relocs));
669 for (i = 0; i < hh[h]->relocs; ) {
670 int count;
671 int shid = hh[h]->reloc[i].shid;
672 for (count = i; count < hh[h]->relocs; count++)
673 if (hh[h]->reloc[count].shid != shid)
674 break;
675 count -= i;
676 wlong(hunk_fd, count);
677 D(bug("\t %d relocations relative to Hunk %d\n", count, hh[shid]->hunk));
678 /* Convert from ELF hunk ID to AOS hunk ID */
679 wlong(hunk_fd, hh[shid]->hunk);
680 for (; count > 0; i++, count--) {
681 D(bug("\t\t%d: 0x%08x %s\n", i, (int)hh[h]->reloc[i].offset, hh[h]->reloc[i].symbol));
682 wlong(hunk_fd, hh[h]->reloc[i].offset);
685 wlong(hunk_fd, 0);
688 static int copy_to(int in, int out)
690 static char buff[64*1024];
691 int len, err = 0;
693 do {
694 len = read(in, buff, sizeof(buff));
695 if (len < 0) {
696 perror("Can't read from input file\n");
697 err = len;
699 if (len == 0)
700 break;
701 } while ((err = write(out, buff, len)) == len);
703 if (err < 0) {
704 perror("Can't write to output file\n");
705 return -errno;
708 return 0;
711 int elf2hunk(int file, int hunk_fd, const char *libname, int flags)
713 const __attribute__((unused)) char *names[3]={ "CODE", "DATA", "BSS" };
714 struct hunkheader **hh;
715 struct elfheader eh;
716 struct sheader *sh;
717 char *strtab = NULL;
718 int symtab_shndx = -1;
719 int err;
720 ULONG i;
721 BOOL exec_hunk_seen __attribute__ ((unused)) = FALSE;
722 ULONG int_shnum;
723 int hunks = 0;
725 /* load and validate ELF header */
726 D(bug("Load header\n"));
727 if ((flags & F_NOCONVERT) || !load_header(file, &eh)) {
728 /* If it's not an ELF, just copy it.
730 * This simplifies a number of mmakefiles
731 * for the m68k-amiga boot and ISO creation
733 lseek(file, 0, SEEK_SET);
734 return (copy_to(file, hunk_fd) == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
737 D(bug("Read SHNum\n"));
738 int_shnum = read_shnum(file, &eh);
739 if (!int_shnum)
740 return EXIT_FAILURE;
742 /* load section headers */
743 D(bug("Load %d Section Headers @0x%08x\n", int_shnum, (int)eh.shoff));
744 if (!(sh = load_block(file, eh.shoff, int_shnum * eh.shentsize)))
745 return EXIT_FAILURE;
747 sh_fixup(sh, int_shnum);
749 /* Looks like we have a valid executable. Generate a
750 * HUNK header set. Not all may be filled in.
752 hh = calloc(sizeof(*hh), int_shnum);
754 /* Look for the string table */
755 D(bug("Look for string table\n"));
756 for (i = 0; i < int_shnum; i++) {
757 if (sh[i].type == SHT_STRTAB) {
758 strtab = load_block(file, sh[i].offset, sh[i].size);
759 break;
763 /* Iterate over the section headers in order to do some stuff... */
764 D(bug("Look for symbol tables\n"));
765 for (i = 0; i < int_shnum; i++)
768 Load the symbol and string table(s).
770 NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states
771 that only one symbol table per file is allowed. However, it
772 also states that this may change in future... we already handle it.
774 D(bug("sh[%d].type = 0x%08x, .offset = 0x%08x, .size = 0x%08x\n",
775 (int)i, (int)sh[i].type, (int)sh[i].offset, (int)sh[i].size));
776 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB || sh[i].type == SHT_SYMTAB_SHNDX)
778 hh[i] = calloc(sizeof(struct hunkheader), 1);
779 hh[i]->type = (sh[i].type == SHT_SYMTAB) ? HUNK_SYMBOL : 0;
780 hh[i]->memflags = 0;
781 hh[i]->hunk = -1;
782 hh[i]->data = load_block(file, sh[i].offset, sh[i].size);
783 if (!hh[i]->data)
784 goto error;
786 if (sh[i].type == SHT_SYMTAB_SHNDX) {
787 if (symtab_shndx == -1)
788 symtab_shndx = i;
789 else
790 D(bug("[ELF2HUNK] file contains multiple symtab shndx tables. only using the first one\n"));
793 else
794 /* Load the section in memory if needed, and make an hunk out of it */
795 if (sh[i].flags & SHF_ALLOC && sh[i].size > 0)
797 hh[i] = calloc(sizeof(struct hunkheader), 1);
798 hh[i]->size = sh[i].size;
799 hh[i]->hunk = hunks++;
801 if (sh[i].type == SHT_NOBITS) {
802 /* BSS area */
803 hh[i]->type = HUNK_BSS;
804 hh[i]->memflags = 0;
805 hh[i]->data = NULL;
806 } else {
807 if (sh[i].flags & SHF_EXECINSTR) {
808 hh[i]->type = HUNK_CODE;
809 exec_hunk_seen = TRUE;
810 } else {
811 hh[i]->type = HUNK_DATA;
813 hh[i]->data = load_block(file, sh[i].offset, sh[i].size);
816 if (strtab) {
817 const char *nameext;
819 D(bug("section %s\n", strtab + sh[i].name));
820 nameext = strrchr(strtab + sh[i].name, '.');
821 if (nameext) {
822 if (strcmp(nameext, ".MEMF_CHIP")==0) {
823 hh[i]->memflags |= MEMF_CHIP;
824 } else if (strcmp(nameext, ".MEMF_LOCAL")==0) {
825 hh[i]->memflags |= MEMF_LOCAL;
826 } else if (strcmp(nameext, ".MEMF_KICK")==0) {
827 hh[i]->memflags |= MEMF_KICK;
828 } else if (strcmp(nameext, ".MEMF_FAST")==0) {
829 hh[i]->memflags |= MEMF_FAST;
836 /* Relocate the sections */
837 D(bug("Convert relocation tables\n"));
838 for (i = 0; i < int_shnum; i++)
840 /* Does this relocation section refer to a hunk? If so, addr must be != 0 */
841 if ((sh[i].type == AROS_ELF_REL)
842 && hh[sh[i].info]
843 && hh[sh[i].info]->data)
845 void *reloc = load_block(file, sh[i].offset, sh[i].size);
847 if (!relocate(&eh, sh, i, symtab_shndx, reloc, hh))
848 return EXIT_FAILURE;
850 free(reloc);
854 D(bug("HUNK_HEADER: \"%s\", hunks=%d, first=%d, last=%d\n", libname, hunks, 0, hunks-1));
856 wlong(hunk_fd, HUNK_HEADER);
857 if (libname == NULL) {
858 wlong(hunk_fd, 0); /* No name */
859 } else {
860 int lsize = (strlen(libname) + 4) / 4;
861 wlong(hunk_fd, lsize);
862 err = write(hunk_fd, libname, lsize * 4);
863 if (err < 0)
864 return EXIT_FAILURE;
866 wlong(hunk_fd, hunks);
867 wlong(hunk_fd, 0); /* First hunk is #0 */
868 wlong(hunk_fd, hunks - 1); /* Last hunk is hunks-1 */
870 /* Write all allocatable hunk sizes */
871 for (i = 0; i < int_shnum; i++) {
872 ULONG count;
874 if (hh[i]==NULL || hh[i]->hunk < 0)
875 continue;
877 count = (hh[i]->size + 4) / 4;
878 switch (hh[i]->memflags) {
879 case MEMF_CHIP:
880 count |= HUNKF_CHIP;
881 break;
882 case MEMF_FAST:
883 count |= HUNKF_FAST;
884 break;
885 case 0:
886 break;
887 default:
888 count |= HUNKF_MEMFLAGS;
889 break;
892 D(bug("\tHunk #%d, %s, lsize=%d\n", hh[i]->hunk, names[hh[i]->type - HUNK_CODE], (int)(hh[i]->size+4)/4));
893 wlong(hunk_fd, count);
895 if ((count & HUNKF_MEMFLAGS) == HUNKF_MEMFLAGS)
896 wlong(hunk_fd, hh[i]->memflags | MEMF_PUBLIC | MEMF_CLEAR);
899 /* Write all hunks */
900 for (i = hunks = 0; i < int_shnum; i++) {
901 D(int s;)
903 if (hh[i]==NULL || hh[i]->hunk < 0)
904 continue;
906 wlong(hunk_fd, hh[i]->type);
907 wlong(hunk_fd, (hh[i]->size + 4) / 4);
909 switch (hh[i]->type) {
910 case HUNK_BSS:
912 bug("HUNK_BSS: %d longs\n", (int)((hh[i]->size + 4) / 4));
913 for (s = 0; s < int_shnum; s++) {
914 if (hh[s] && hh[s]->type == HUNK_SYMBOL)
915 sym_dump(hunk_fd, sh, hh, i, s);
919 wlong(hunk_fd, HUNK_END);
920 hunks++;
921 break;
922 case HUNK_CODE:
923 case HUNK_DATA:
924 D(bug("#%d HUNK_%s: %d longs\n", hh[i]->hunk, hh[i]->type == HUNK_CODE ? "CODE" : "DATA", (int)((hh[i]->size + 4) / 4)));
925 err = write(hunk_fd, hh[i]->data, ((hh[i]->size + 4)/4)*4);
926 if (err < 0)
927 return EXIT_FAILURE;
929 for (s = 0; s < int_shnum; s++) {
930 if (hh[s] && hh[s]->type == HUNK_SYMBOL)
931 sym_dump(hunk_fd, sh, hh, i, s);
934 reloc_dump(hunk_fd, hh, i);
935 wlong(hunk_fd, HUNK_END);
936 D(bug("\tHUNK_END\n"));
937 break;
938 default:
939 D(bug("Unsupported allocatable hunk type %d\n", (int)hh[i]->type));
940 return EXIT_FAILURE;
944 /* Free all blocks */
945 for (i = 0; i < int_shnum; i++) {
946 if (hh[i]) {
947 if (hh[i]->data)
948 free(hh[i]->data);
949 if (hh[i]->reloc)
950 free(hh[i]->reloc);
951 free(hh[i]);
954 free(hh);
955 free(sh);
957 if (strtab)
958 free(strtab);
960 D(bug("All good, all done.\n"));
961 return EXIT_SUCCESS;
963 error:
964 return EXIT_FAILURE;
967 static int copy(const char *src, const char *dst, int flags);
969 static BOOL valid_dir(const char *dir)
971 /* Don't convert anything in a Developer directory */
972 if (strcasecmp(dir, "Developer") == 0)
973 return FALSE;
974 return TRUE;
977 static int copy_dir(const char *src, const char *dst, int flags)
979 DIR *sdir;
980 struct dirent *de;
981 char spath[PATH_MAX], dpath[PATH_MAX];
982 char *sp, *dp;
983 int sleft, dleft;
984 int err = EXIT_SUCCESS;
986 sdir = opendir(src);
987 if (sdir == NULL) {
988 perror(src);
989 return EXIT_FAILURE;
992 snprintf(spath, sizeof(spath), "%s/", src);
993 spath[sizeof(spath)-1] = 0;
994 sp = &spath[strlen(spath)];
995 sleft = &spath[sizeof(spath)-1] - sp;
997 snprintf(dpath, sizeof(dpath), "%s/", dst);
998 dpath[sizeof(dpath)-1] = 0;
999 dp = &dpath[strlen(dpath)];
1000 dleft = &dpath[sizeof(dpath)-1] - dp;
1002 while ((de = readdir(sdir)) != NULL) {
1003 int eflags = 0;
1005 if ((strcmp(de->d_name, ".") == 0) ||
1006 (strcmp(de->d_name, "..") == 0))
1007 continue;
1009 /* Don't convert anything if its an invalid directory */
1010 if (!valid_dir(de->d_name))
1011 eflags |= F_NOCONVERT;
1013 strncpy(sp, de->d_name, sleft);
1014 sp[sleft-1] = 0;
1015 strncpy(dp, de->d_name, dleft);
1016 dp[dleft-1] = 0;
1017 err = copy(spath, dpath, flags | eflags);
1018 if (err != EXIT_SUCCESS)
1019 break;
1022 closedir(sdir);
1024 return err;
1027 static int copy(const char *src, const char *dst, int flags)
1029 int src_fd, hunk_fd;
1030 struct stat st;
1031 int mode, ret;
1033 if (flags & F_VERBOSE)
1034 printf("%s ->\n %s\n", src, dst);
1036 if (stat(src, &st) >= 0) {
1037 mode = st.st_mode;
1038 } else {
1039 mode = 0755;
1042 if (S_ISDIR(mode)) {
1043 unlink(dst);
1044 mkdir(dst, mode);
1045 return copy_dir(src, dst, flags);
1048 src_fd = open(src, O_RDONLY);
1049 if (src_fd < 0) {
1050 perror(src);
1051 return EXIT_FAILURE;
1054 if (strcmp(dst,"-") == 0)
1055 hunk_fd = 1; /* stdout */
1056 else {
1057 unlink(dst);
1058 hunk_fd = open(dst, O_RDWR | O_CREAT | O_TRUNC, mode);
1060 if (hunk_fd < 0) {
1061 perror(dst);
1062 return EXIT_FAILURE;
1065 ret = elf2hunk(src_fd, hunk_fd, NULL, flags);
1066 if (ret != 0)
1067 perror(src);
1069 close(src_fd);
1070 if (hunk_fd != 1)
1071 close(hunk_fd);
1073 return ret;
1076 int main(int argc, char **argv)
1078 int flags = 0;
1080 if (argc == 4 && strcmp(argv[1],"-v") == 0) {
1081 flags |= F_VERBOSE;
1082 argc--;
1083 argv++;
1086 if (argc != 3) {
1087 fprintf(stderr, "Usage:\n%s file.elf file.hunk\n", argv[0]);
1088 fprintf(stderr, "%s src-dir dest-dir\n", argv[0]);
1089 return EXIT_FAILURE;
1092 return copy(argv[1], argv[2], flags);