nld: loaded sections should not share a page
[ld.git] / nld.c
blobfad1f8c7020c883caefe54a996bad852d68223de
1 /*
2 * NEATLD ARM/X86(-64) STATIC LINKER
4 * Copyright (C) 2010-2018 Ali Gholami Rudi
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <ctype.h>
19 #include <elf.h>
20 #include <fcntl.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/stat.h>
24 #include <string.h>
25 #include <unistd.h>
27 #define I_CS 0
28 #define I_DS 1
29 #define I_BSS 2
31 static unsigned long sec_vaddr[3] = {0x800000}; /* virtual address of sections */
32 static unsigned long sec_laddr[3] = {0x800000}; /* load address of sections */
33 static int sec_set[3] = {1}; /* set address for section */
34 static int secalign = 16; /* section alignment */
35 static char *entry = "_start"; /* entry symbol */
36 static int e_machine; /* target machine */
37 static int e_flags; /* elf ehdr flags */
39 #define MAXSECS (1 << 10)
40 #define MAXOBJS (1 << 7)
41 #define MAXSYMS (1 << 12)
42 #define PAGE_SIZE (1 << 12)
43 #define PAGE_MASK (PAGE_SIZE - 1)
44 #define MAXFILES (1 << 10)
45 #define MAXPHDRS 4
47 #define MAX(a, b) ((a) > (b) ? (a) : (b))
48 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
50 /* simplified elf struct and macro names */
51 #ifdef __x86_64__
52 # define Elf_Phdr Elf64_Phdr
53 # define Elf_Ehdr Elf64_Ehdr
54 # define Elf_Shdr Elf64_Shdr
55 # define Elf_Sym Elf64_Sym
56 # define Elf_Rela Elf64_Rela
57 # define SHT_REL_ SHT_RELA
58 # define REL_ADDEND(r) ((r)->r_addend)
59 # define ELF_ST_INFO ELF64_ST_INFO
60 # define ELF_ST_BIND ELF64_ST_BIND
61 # define ELF_R_SYM ELF64_R_SYM
62 # define ELF_R_TYPE ELF64_R_TYPE
63 # define ELF_ST_TYPE ELF64_ST_TYPE
64 #else
65 # define Elf_Phdr Elf32_Phdr
66 # define Elf_Ehdr Elf32_Ehdr
67 # define Elf_Shdr Elf32_Shdr
68 # define Elf_Sym Elf32_Sym
69 # define Elf_Rela Elf32_Rel
70 # define SHT_REL_ SHT_REL
71 # define REL_ADDEND(r) (0)
72 # define ELF_ST_INFO ELF32_ST_INFO
73 # define ELF_ST_BIND ELF32_ST_BIND
74 # define ELF_R_SYM ELF32_R_SYM
75 # define ELF_R_TYPE ELF32_R_TYPE
76 # define ELF_ST_TYPE ELF32_ST_TYPE
77 #endif
79 struct obj {
80 char *mem;
81 Elf_Ehdr *ehdr;
82 Elf_Shdr *shdr;
83 Elf_Sym *syms;
84 int nsyms;
85 char *symstr;
86 char *shstr;
89 struct secmap {
90 Elf_Shdr *o_shdr;
91 struct obj *obj;
92 unsigned long vaddr;
93 unsigned long faddr;
96 struct bss_sym {
97 Elf_Sym *sym;
98 int off;
101 struct outelf {
102 Elf_Ehdr ehdr;
103 Elf_Phdr phdr[MAXSECS];
104 int nph;
105 struct secmap secs[MAXSECS];
106 int nsecs;
107 struct obj objs[MAXOBJS];
108 int nobjs;
110 /* code section */
111 unsigned long code_addr;
113 /* bss section */
114 struct bss_sym bss_syms[MAXSYMS];
115 int nbss_syms;
116 unsigned long bss_vaddr;
117 int bss_len;
119 /* symtab section */
120 Elf_Shdr shdr[MAXSECS];
121 int nsh;
122 char symstr[MAXSYMS];
123 Elf_Sym syms[MAXSYMS];
124 int nsyms;
125 int nsymstr;
126 unsigned long shdr_faddr;
127 unsigned long syms_faddr;
128 unsigned long symstr_faddr;
131 static int nosyms = 0;
133 static Elf_Sym *obj_find(struct obj *obj, char *name)
135 int i;
136 for (i = 0; i < obj->nsyms; i++) {
137 Elf_Sym *sym = &obj->syms[i];
138 if (ELF_ST_BIND(sym->st_info) == STB_LOCAL ||
139 sym->st_shndx == SHN_UNDEF)
140 continue;
141 if (!strcmp(name, obj->symstr + sym->st_name))
142 return sym;
144 return NULL;
147 static void obj_init(struct obj *obj, char *mem)
149 int i;
150 obj->mem = mem;
151 obj->ehdr = (void *) mem;
152 obj->shdr = (void *) (mem + obj->ehdr->e_shoff);
153 obj->shstr = mem + obj->shdr[obj->ehdr->e_shstrndx].sh_offset;
154 for (i = 0; i < obj->ehdr->e_shnum; i++) {
155 if (obj->shdr[i].sh_type != SHT_SYMTAB)
156 continue;
157 obj->symstr = mem + obj->shdr[obj->shdr[i].sh_link].sh_offset;
158 obj->syms = (void *) (mem + obj->shdr[i].sh_offset);
159 obj->nsyms = obj->shdr[i].sh_size / sizeof(*obj->syms);
163 static void outelf_init(struct outelf *oe)
165 memset(oe, 0, sizeof(*oe));
166 oe->ehdr.e_ident[0] = 0x7f;
167 oe->ehdr.e_ident[1] = 'E';
168 oe->ehdr.e_ident[2] = 'L';
169 oe->ehdr.e_ident[3] = 'F';
170 oe->ehdr.e_ident[4] = sizeof(long) == 8 ? ELFCLASS64 : ELFCLASS32;
171 oe->ehdr.e_ident[5] = ELFDATA2LSB;
172 oe->ehdr.e_ident[6] = EV_CURRENT;
173 oe->ehdr.e_type = ET_EXEC;
174 oe->ehdr.e_version = EV_CURRENT;
175 oe->ehdr.e_shstrndx = SHN_UNDEF;
176 oe->ehdr.e_ehsize = sizeof(oe->ehdr);
177 oe->ehdr.e_phentsize = sizeof(oe->phdr[0]);
178 oe->ehdr.e_shentsize = sizeof(Elf_Shdr);
181 static struct secmap *outelf_mapping(struct outelf *oe, Elf_Shdr *shdr)
183 int i;
184 for (i = 0; i < oe->nsecs; i++)
185 if (oe->secs[i].o_shdr == shdr)
186 return &oe->secs[i];
187 return NULL;
190 static int outelf_find(struct outelf *oe, char *name,
191 struct obj **sym_obj, Elf_Sym **sym_sym)
193 int i;
194 for (i = 0; i < oe->nobjs; i++) {
195 struct obj *obj = &oe->objs[i];
196 Elf_Sym *sym;
197 if ((sym = obj_find(obj, name))) {
198 *sym_obj = obj;
199 *sym_sym = sym;
200 return 0;
203 return 1;
206 static unsigned long bss_addr(struct outelf *oe, Elf_Sym *sym)
208 int i;
209 for (i = 0; i < oe->nbss_syms; i++)
210 if (oe->bss_syms[i].sym == sym)
211 return oe->bss_vaddr + oe->bss_syms[i].off;
212 return 0;
215 static void die(char *msg)
217 fprintf(stderr, "%s\n", msg);
218 exit(1);
221 static void die_undef(char *name)
223 fprintf(stderr, "%s undefined\n", name);
224 exit(1);
227 static unsigned long symval(struct outelf *oe, struct obj *obj, Elf_Sym *sym)
229 struct secmap *sec;
230 char *name = obj ? obj->symstr + sym->st_name : NULL;
231 int s_idx, s_off;
232 switch (ELF_ST_TYPE(sym->st_info)) {
233 case STT_SECTION:
234 if ((sec = outelf_mapping(oe, &obj->shdr[sym->st_shndx])))
235 return sec->vaddr;
236 break;
237 case STT_NOTYPE:
238 case STT_OBJECT:
239 case STT_FUNC:
240 if (name && *name && sym->st_shndx == SHN_UNDEF)
241 if (outelf_find(oe, name, &obj, &sym))
242 die_undef(name);
243 if (sym->st_shndx == SHN_COMMON)
244 return bss_addr(oe, sym);
245 s_idx = sym->st_shndx;
246 s_off = sym->st_value;
247 sec = outelf_mapping(oe, &obj->shdr[s_idx]);
248 if ((sec = outelf_mapping(oe, &obj->shdr[s_idx])))
249 return sec->vaddr + s_off;
251 return 0;
254 static unsigned long outelf_addr(struct outelf *oe, char *name)
256 struct obj *obj;
257 Elf_Sym *sym;
258 if (outelf_find(oe, name, &obj, &sym))
259 die_undef(name);
260 return symval(oe, obj, sym);
263 #define REL_ARM 0x10000
264 #define REL_X64 0x20000
265 #define REL_X86 0x40000
267 static int arch_rel(int r)
269 if (e_machine == EM_ARM)
270 return REL_ARM | r;
271 if (e_machine == EM_X86_64)
272 return REL_X64 | r;
273 if (e_machine == EM_386)
274 return REL_X86 | r;
275 return 0;
278 static void outelf_reloc_sec(struct outelf *oe, int o_idx, int s_idx)
280 struct obj *obj = &oe->objs[o_idx];
281 Elf_Shdr *rel_shdr = &obj->shdr[s_idx];
282 Elf_Rela *rels = (void *) obj->mem + obj->shdr[s_idx].sh_offset;
283 Elf_Shdr *other_shdr = &obj->shdr[rel_shdr->sh_info];
284 void *other = (void *) obj->mem + other_shdr->sh_offset;
285 int nrels = rel_shdr->sh_size / sizeof(*rels);
286 unsigned long addr;
287 int i;
288 for (i = 0; i < nrels; i++) {
289 Elf_Rela *rel = (void *) &rels[i];
290 int sym_idx = ELF_R_SYM(rel->r_info);
291 Elf_Sym *sym = &obj->syms[sym_idx];
292 unsigned long val = symval(oe, obj, sym) + REL_ADDEND(rel);
293 unsigned long *dst = other + rel->r_offset;
294 switch (arch_rel(ELF_R_TYPE(rel->r_info))) {
295 case REL_ARM | R_ARM_NONE:
296 case REL_X86 | R_386_NONE:
297 case REL_X64 | R_X86_64_NONE:
298 break;
299 case REL_ARM | R_ARM_ABS16:
300 case REL_X86 | R_386_16:
301 case REL_X64 | R_X86_64_16:
302 *(unsigned short *) dst += val;
303 break;
304 case REL_ARM | R_ARM_ABS32:
305 case REL_X86 | R_386_32:
306 case REL_X64 | R_X86_64_32:
307 case REL_X64 | R_X86_64_32S:
308 *(unsigned int *) dst += val;
309 break;
310 case REL_X64 | R_X86_64_64:
311 *dst += val;
312 break;
313 case REL_ARM | R_ARM_REL32:
314 case REL_ARM | R_ARM_PLT32:
315 case REL_X86 | R_386_PLT32:
316 case REL_X86 | R_386_PC32:
317 case REL_X64 | R_X86_64_PC32:
318 addr = outelf_mapping(oe, other_shdr)->vaddr +
319 rel->r_offset;
320 *(unsigned int *) dst += val - addr;
321 break;
322 case REL_ARM | R_ARM_PC24:
323 addr = outelf_mapping(oe, other_shdr)->vaddr +
324 rel->r_offset;
325 *dst = (*dst & 0xff000000) |
326 ((*dst + ((val - addr) >> 2)) & 0x00ffffff);
327 break;
328 default:
329 die("neatld: unknown relocation type!");
334 static void outelf_reloc(struct outelf *oe)
336 int i, j;
337 for (i = 0; i < oe->nobjs; i++) {
338 struct obj *obj = &oe->objs[i];
339 for (j = 0; j < obj->ehdr->e_shnum; j++)
340 if (obj->shdr[j].sh_type == SHT_REL_)
341 outelf_reloc_sec(oe, i, j);
345 static void alloc_bss(struct outelf *oe, Elf_Sym *sym)
347 int n = oe->nbss_syms++;
348 int off = ALIGN(oe->bss_len, MAX(sym->st_value, 4));
349 oe->bss_syms[n].sym = sym;
350 oe->bss_syms[n].off = off;
351 oe->bss_len = off + sym->st_size;
354 static void outelf_bss(struct outelf *oe)
356 int i, j;
357 for (i = 0; i < oe->nobjs; i++) {
358 struct obj *obj = &oe->objs[i];
359 for (j = 0; j < obj->nsyms; j++)
360 if (obj->syms[j].st_shndx == SHN_COMMON)
361 alloc_bss(oe, &obj->syms[j]);
365 #define SEC_CODE(s) ((s)->sh_flags & SHF_EXECINSTR)
366 #define SEC_BSS(s) ((s)->sh_type == SHT_NOBITS)
367 #define SEC_DATA(s) (!SEC_CODE(s) && !SEC_BSS(s))
369 static char *putstr(char *d, char *s)
371 while (*s)
372 *d++ = *s++;
373 *d++ = '\0';
374 return d;
377 static void build_symtab(struct outelf *oe)
379 int i, j;
380 char *symstr = oe->symstr;
381 Elf_Sym *syms = oe->syms;
382 Elf_Shdr *sym_shdr = &oe->shdr[1];
383 Elf_Shdr *str_shdr = &oe->shdr[2];
384 int n = 1;
385 char *s = putstr(symstr, "");
386 int faddr = oe->shdr_faddr;
387 oe->nsh = 3;
388 for (i = 0; i < oe->nobjs; i++) {
389 struct obj *obj = &oe->objs[i];
390 for (j = 0; j < obj->nsyms; j++) {
391 Elf_Sym *sym = &obj->syms[j];
392 int type = ELF_ST_TYPE(sym->st_info);
393 int bind = ELF_ST_BIND(sym->st_info);
394 char *name = obj->symstr + sym->st_name;
395 if (!*name || bind == STB_LOCAL ||
396 sym->st_shndx == SHN_UNDEF)
397 continue;
398 syms[n].st_name = s - symstr;
399 s = putstr(s, name);
400 syms[n].st_info = ELF_ST_INFO(bind, type);
401 syms[n].st_value = symval(oe, obj, sym);
402 syms[n].st_size = sym->st_size;
403 syms[n].st_shndx = SHN_ABS;
404 n++;
407 oe->nsymstr = s - symstr;
408 oe->nsyms = n;
410 oe->shdr_faddr = faddr;
411 faddr += oe->nsh * sizeof(oe->shdr[0]);
412 oe->syms_faddr = faddr;
413 faddr += oe->nsyms * sizeof(oe->syms[0]);
414 oe->symstr_faddr = faddr;
415 faddr += oe->nsymstr;
417 oe->ehdr.e_shstrndx = str_shdr - oe->shdr;
418 oe->ehdr.e_shoff = oe->shdr_faddr;
419 oe->ehdr.e_shnum = oe->nsh;
421 str_shdr->sh_name = 0;
422 str_shdr->sh_type = SHT_STRTAB;
423 str_shdr->sh_offset = oe->symstr_faddr;
424 str_shdr->sh_size = oe->nsymstr;
426 sym_shdr->sh_name = 0;
427 sym_shdr->sh_type = SHT_SYMTAB;
428 sym_shdr->sh_entsize = sizeof(oe->syms[0]);
429 sym_shdr->sh_offset = oe->syms_faddr;
430 sym_shdr->sh_size = oe->nsyms * sizeof(oe->syms[0]);
431 sym_shdr->sh_link = str_shdr - oe->shdr;
432 sym_shdr->sh_info = 0;
435 static void outelf_write(struct outelf *oe, int fd)
437 int i;
438 oe->ehdr.e_entry = outelf_addr(oe, entry) -
439 sec_vaddr[I_CS] + sec_laddr[I_CS];
440 if (!nosyms)
441 build_symtab(oe);
442 oe->ehdr.e_phnum = oe->nph;
443 oe->ehdr.e_phoff = sizeof(oe->ehdr);
444 oe->ehdr.e_machine = e_machine;
445 oe->ehdr.e_flags = e_flags;
446 lseek(fd, 0, SEEK_SET);
447 write(fd, &oe->ehdr, sizeof(oe->ehdr));
448 write(fd, &oe->phdr, oe->nph * sizeof(oe->phdr[0]));
449 for (i = 0; i < oe->nsecs; i++) {
450 struct secmap *sec = &oe->secs[i];
451 char *buf = sec->obj->mem + sec->o_shdr->sh_offset;
452 int len = sec->o_shdr->sh_size;
453 if (SEC_BSS(sec->o_shdr))
454 continue;
455 lseek(fd, sec->faddr, SEEK_SET);
456 write(fd, buf, len);
458 if (!nosyms) {
459 lseek(fd, oe->shdr_faddr, SEEK_SET);
460 write(fd, &oe->shdr, oe->nsh * sizeof(oe->shdr[0]));
461 lseek(fd, oe->syms_faddr, SEEK_SET);
462 write(fd, &oe->syms, oe->nsyms * sizeof(oe->syms[0]));
463 lseek(fd, oe->symstr_faddr, SEEK_SET);
464 write(fd, &oe->symstr, oe->nsymstr);
468 static void outelf_add(struct outelf *oe, char *mem)
470 Elf_Ehdr *ehdr = (void *) mem;
471 Elf_Shdr *shdr = (void *) (mem + ehdr->e_shoff);
472 struct obj *obj;
473 int i;
474 if (ehdr->e_type != ET_REL)
475 return;
476 e_machine = ehdr->e_machine;
477 e_flags = ehdr->e_flags;
478 if (oe->nobjs >= MAXOBJS)
479 die("neatld: MAXOBJS reached!");
480 obj = &oe->objs[oe->nobjs++];
481 obj_init(obj, mem);
482 for (i = 0; i < ehdr->e_shnum; i++) {
483 struct secmap *sec;
484 if (!(shdr[i].sh_flags & 0x7))
485 continue;
486 if (oe->nsecs >= MAXSECS)
487 die("neatld: MAXSECS reached!");
488 sec = &oe->secs[oe->nsecs++];
489 sec->o_shdr = &shdr[i];
490 sec->obj = obj;
494 static int link_cs(struct outelf *oe, Elf_Phdr *phdr, unsigned long faddr,
495 unsigned long vaddr, unsigned long laddr, int len)
497 int i;
498 for (i = 0; i < oe->nsecs; i++) {
499 struct secmap *sec = &oe->secs[i];
500 int alignment = MAX(sec->o_shdr->sh_addralign, 4);
501 if (!SEC_CODE(sec->o_shdr))
502 continue;
503 len = ALIGN(vaddr + len, alignment) - vaddr;
504 sec->vaddr = vaddr + len;
505 sec->faddr = faddr + len;
506 len += sec->o_shdr->sh_size;
508 phdr->p_type = PT_LOAD;
509 phdr->p_flags = PF_R | PF_W | PF_X;
510 phdr->p_vaddr = vaddr;
511 phdr->p_paddr = laddr;
512 phdr->p_offset = faddr;
513 phdr->p_filesz = len;
514 phdr->p_memsz = len;
515 phdr->p_align = PAGE_SIZE;
516 return len;
519 static int link_ds(struct outelf *oe, Elf_Phdr *phdr, unsigned long faddr,
520 unsigned long vaddr, unsigned long laddr)
522 int len = 0;
523 int i;
524 for (i = 0; i < oe->nsecs; i++) {
525 struct secmap *sec = &oe->secs[i];
526 if (!SEC_DATA(sec->o_shdr))
527 continue;
528 sec->vaddr = vaddr + len;
529 sec->faddr = faddr + len;
530 len += sec->o_shdr->sh_size;
532 len = ALIGN(len, 4);
533 phdr->p_type = PT_LOAD;
534 phdr->p_flags = PF_R | PF_W | PF_X;
535 phdr->p_align = PAGE_SIZE;
536 phdr->p_vaddr = vaddr;
537 phdr->p_paddr = laddr;
538 phdr->p_filesz = len;
539 phdr->p_memsz = len;
540 phdr->p_offset = faddr;
541 return len;
544 static int link_bss(struct outelf *oe, Elf_Phdr *phdr,
545 unsigned long faddr, unsigned long vaddr, int len)
547 int i;
548 for (i = 0; i < oe->nsecs; i++) {
549 struct secmap *sec = &oe->secs[i];
550 int alignment = MAX(sec->o_shdr->sh_addralign, 4);
551 if (!SEC_BSS(sec->o_shdr))
552 continue;
553 len = ALIGN(vaddr + len, alignment) - vaddr;
554 sec->vaddr = vaddr + len;
555 sec->faddr = faddr;
556 len += sec->o_shdr->sh_size;
558 phdr->p_type = PT_LOAD;
559 phdr->p_flags = PF_R | PF_W;
560 phdr->p_vaddr = vaddr;
561 phdr->p_paddr = vaddr;
562 phdr->p_offset = faddr;
563 phdr->p_filesz = 0;
564 phdr->p_memsz = len;
565 phdr->p_align = PAGE_SIZE;
566 return len;
569 static void outelf_link(struct outelf *oe)
571 unsigned long faddr, vaddr, laddr;
572 int len;
573 len = ALIGN(sizeof(oe->ehdr) + MAXPHDRS * sizeof(oe->phdr[0]), secalign);
574 faddr = len & ~PAGE_MASK;
575 vaddr = sec_vaddr[I_CS];
576 laddr = sec_laddr[I_CS];
577 len = link_cs(oe, &oe->phdr[0], faddr, vaddr, laddr, len & PAGE_MASK);
579 len = ALIGN(faddr + len, secalign) - faddr;
580 faddr += len;
581 vaddr = sec_set[I_DS] ? sec_vaddr[I_DS] | (faddr & PAGE_MASK) :
582 vaddr + PAGE_SIZE + len;
583 laddr = sec_set[I_DS] ? sec_laddr[I_DS] | (faddr & PAGE_MASK) :
584 laddr + PAGE_SIZE + len;
585 len = link_ds(oe, &oe->phdr[1], faddr, vaddr, laddr);
587 len = ALIGN(faddr + len, secalign) - faddr;
588 faddr += len;
589 vaddr = sec_set[I_BSS] ? sec_vaddr[I_BSS] | (faddr & PAGE_MASK) :
590 vaddr + PAGE_SIZE + len;
591 outelf_bss(oe);
592 oe->bss_vaddr = vaddr;
593 len = link_bss(oe, &oe->phdr[2], faddr, vaddr, oe->bss_len);
595 oe->nph = 3;
596 outelf_reloc(oe);
597 oe->shdr_faddr = faddr;
600 struct arhdr {
601 char ar_name[16];
602 char ar_date[12];
603 char ar_uid[6];
604 char ar_gid[6];
605 char ar_mode[8];
606 char ar_size[10];
607 char ar_fmag[2];
610 static int get_be32(unsigned char *s)
612 return s[3] | (s[2] << 8) | (s[1] << 16) | (s[0] << 24);
615 static int sym_undef(struct outelf *oe, char *name)
617 int i, j;
618 int undef = 0;
619 for (i = 0; i < oe->nobjs; i++) {
620 struct obj *obj = &oe->objs[i];
621 for (j = 0; j < obj->nsyms; j++) {
622 Elf_Sym *sym = &obj->syms[j];
623 if (ELF_ST_BIND(sym->st_info) == STB_LOCAL)
624 continue;
625 if (strcmp(name, obj->symstr + sym->st_name))
626 continue;
627 if (sym->st_shndx != SHN_UNDEF)
628 return 0;
629 undef = 1;
632 return undef;
635 static int outelf_ar_link(struct outelf *oe, char *ar, int base)
637 char *ar_index;
638 char *ar_name;
639 int nsyms = get_be32((void *) ar);
640 int added = 0;
641 int i;
642 ar_index = ar + 4;
643 ar_name = ar_index + nsyms * 4;
644 for (i = 0; i < nsyms; i++) {
645 int off = get_be32((void *) ar_index + i * 4) +
646 sizeof(struct arhdr);
647 if (sym_undef(oe, ar_name)) {
648 outelf_add(oe, ar - base + off);
649 added++;
651 ar_name = strchr(ar_name, '\0') + 1;
653 return added;
656 static void outelf_archive(struct outelf *oe, char *ar)
658 char *beg = ar;
660 /* skip magic */
661 ar += 8;
662 for(;;) {
663 struct arhdr *hdr = (void *) ar;
664 char *name = hdr->ar_name;
665 int size;
666 ar += sizeof(*hdr);
667 hdr->ar_size[sizeof(hdr->ar_size) - 1] = '\0';
668 size = atoi(hdr->ar_size);
669 size = (size + 1) & ~1;
670 if (name[0] == '/' && name[1] == ' ') {
671 while (outelf_ar_link(oe, ar, ar - beg))
673 return;
675 if (name[0] == '/' && name[1] == '/' && name[2] == ' ')
676 outelf_add(oe, ar);
677 ar += size;
681 static long filesize(int fd)
683 struct stat stat;
684 fstat(fd, &stat);
685 return stat.st_size;
688 static char *fileread(char *path)
690 int fd = open(path, O_RDONLY);
691 int size = filesize(fd);
692 char *buf = malloc(size);
693 read(fd, buf, size);
694 close(fd);
695 return buf;
698 static int is_ar(char *path)
700 int len = strlen(path);
701 return len > 2 && path[len - 2] == '.' && path[len - 1] == 'a';
704 #define LIBDIRS (1 << 5)
705 #define PATHLEN (1 << 8)
707 static char *libdirs[LIBDIRS] = {"/lib"};
708 static int nlibdirs = 1;
710 static int lib_find(char *path, char *lib)
712 struct stat st;
713 int i;
714 for (i = 0; i < nlibdirs; i++) {
715 sprintf(path, "%s/lib%s.a", libdirs[i], lib);
716 if (!stat(path, &st))
717 return 0;
719 return 1;
722 static unsigned long hexnum(char *s)
724 unsigned long n = 0;
725 if (s[0] == '0' && s[1] == 'x')
726 s += 2;
727 for (; isdigit(*s) || isalpha(*s); s++) {
728 n <<= 4;
729 n |= isdigit(*s) ? *s - '0' : tolower(*s) - 'a' + 10;
731 return n;
734 static void set_addr(int sec, char *arg)
736 int idx = I_CS;
737 char *sep = strchr(arg, ':');
738 if (sec == 'd')
739 idx = I_DS;
740 if (sec == 'b')
741 idx = I_BSS;
742 sec_vaddr[idx] = hexnum(arg);
743 sec_laddr[idx] = sep ? hexnum(sep + 1) : sec_vaddr[idx];
744 sec_set[idx] = 1;
747 static char *obj_add(struct outelf *oe, char *path)
749 char *buf = fileread(path);
750 if (!buf)
751 die("neatld: cannot open object!");
752 if (is_ar(path))
753 outelf_archive(oe, buf);
754 else
755 outelf_add(oe, buf);
756 return buf;
759 int main(int argc, char **argv)
761 char out[PATHLEN] = "a.out";
762 struct outelf oe;
763 char *mem[MAXFILES];
764 int nmem = 0;
765 int fd;
766 int i = 0;
767 if (argc < 2)
768 die("neatld: no object given!");
769 outelf_init(&oe);
771 while (++i < argc) {
772 if (argv[i][0] != '-') {
773 mem[nmem++] = obj_add(&oe, argv[i]);
774 continue;
776 if (argv[i][1] == 'l') {
777 char path[PATHLEN];
778 if (lib_find(path, argv[i] + 2))
779 die("neatld: cannot find library!");
780 mem[nmem++] = obj_add(&oe, path);
781 continue;
783 if (argv[i][1] == 'L') {
784 libdirs[nlibdirs++] = argv[i][2] ? argv[i] + 2 : argv[++i];
785 continue;
787 if (argv[i][1] == 'o') {
788 strcpy(out, argv[i][2] ? argv[i] + 2 : argv[++i]);
789 continue;
791 if (argv[i][1] == 's') {
792 nosyms = 1;
793 continue;
795 if (argv[i][1] == 'g')
796 continue;
797 if (argv[i][1] == 'm') {
798 char sec = argv[i][2];
799 char *arg = argv[i][3] == '=' ? argv[i] + 4 : argv[++i];
800 set_addr(sec, arg);
801 continue;
803 if (argv[i][1] == 'p') {
804 secalign = PAGE_SIZE;
805 continue;
807 if (argv[i][1] == 'e') {
808 entry = argv[i][2] ? argv[i] + 2 : argv[++i];
809 continue;
811 if (argv[i][1] == 'h') {
812 printf("Usage: neatld [options] objects\n");
813 return 1;
816 outelf_link(&oe);
817 fd = open(out, O_WRONLY | O_TRUNC | O_CREAT, 0700);
818 if (fd < 0)
819 die("neatld: failed to create the output!");
820 outelf_write(&oe, fd);
821 close(fd);
822 for (i = 0; i < nmem; i++)
823 free(mem[i]);
824 return 0;