nld: list options with -h
[ld.git] / nld.c
blobdce5ac5838cd394e17e2cefbbc42b039ed3b1f56
1 /*
2 * NEATLD ARM/X86(-64) STATIC LINKER
4 * Copyright (C) 2010-2023 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 int outelf_str(struct outelf *oe, char *s)
371 int n = oe->nsymstr;
372 char *d = oe->symstr + oe->nsymstr;
373 while (*s)
374 *d++ = *s++;
375 *d++ = '\0';
376 oe->nsymstr = d - oe->symstr;
377 return n;
380 static void build_symtab(struct outelf *oe)
382 int i, j;
383 Elf_Sym *syms = oe->syms;
384 Elf_Shdr *cs_shdr = &oe->shdr[++oe->nsh];
385 Elf_Shdr *ds_shdr = &oe->shdr[++oe->nsh];
386 Elf_Shdr *bss_shdr = &oe->shdr[++oe->nsh];
387 Elf_Shdr *sym_shdr = &oe->shdr[++oe->nsh];
388 Elf_Shdr *str_shdr = &oe->shdr[++oe->nsh];
389 int n = 1;
390 int faddr = oe->shdr_faddr;
391 oe->nsh++;
392 outelf_str(oe, "");
393 sym_shdr->sh_name = outelf_str(oe, ".symtab");
394 str_shdr->sh_name = outelf_str(oe, ".strtab");
395 cs_shdr->sh_name = outelf_str(oe, ".text");
396 ds_shdr->sh_name = outelf_str(oe, ".data");
397 bss_shdr->sh_name = outelf_str(oe, ".bss");
398 for (i = 0; i < oe->nobjs; i++) {
399 struct obj *obj = &oe->objs[i];
400 for (j = 0; j < obj->nsyms; j++) {
401 Elf_Sym *sym = &obj->syms[j];
402 int type = ELF_ST_TYPE(sym->st_info);
403 int bind = ELF_ST_BIND(sym->st_info);
404 char *name = obj->symstr + sym->st_name;
405 if (!*name || bind == STB_LOCAL ||
406 sym->st_shndx == SHN_UNDEF)
407 continue;
408 syms[n].st_name = outelf_str(oe, name);
409 syms[n].st_info = ELF_ST_INFO(bind, type);
410 syms[n].st_value = symval(oe, obj, sym);
411 syms[n].st_size = sym->st_size;
412 syms[n].st_shndx = SHN_ABS;
413 n++;
416 oe->nsyms = n;
418 oe->shdr_faddr = faddr;
419 faddr += oe->nsh * sizeof(oe->shdr[0]);
420 oe->syms_faddr = faddr;
421 faddr += oe->nsyms * sizeof(oe->syms[0]);
422 oe->symstr_faddr = faddr;
423 faddr += oe->nsymstr;
425 oe->ehdr.e_shstrndx = str_shdr - oe->shdr;
426 oe->ehdr.e_shoff = oe->shdr_faddr;
427 oe->ehdr.e_shnum = oe->nsh;
429 str_shdr->sh_type = SHT_STRTAB;
430 str_shdr->sh_offset = oe->symstr_faddr;
431 str_shdr->sh_size = oe->nsymstr;
433 sym_shdr->sh_type = SHT_SYMTAB;
434 sym_shdr->sh_entsize = sizeof(oe->syms[0]);
435 sym_shdr->sh_offset = oe->syms_faddr;
436 sym_shdr->sh_size = oe->nsyms * sizeof(oe->syms[0]);
437 sym_shdr->sh_link = str_shdr - oe->shdr;
438 sym_shdr->sh_info = 0;
440 cs_shdr->sh_type = SHT_PROGBITS;
441 cs_shdr->sh_flags = SHF_ALLOC | SHF_EXECINSTR;
442 cs_shdr->sh_offset = oe->phdr[I_CS].p_offset;
443 cs_shdr->sh_addr = oe->phdr[I_CS].p_vaddr;
444 cs_shdr->sh_addralign = oe->phdr[I_CS].p_align;
445 cs_shdr->sh_size = oe->phdr[I_CS].p_filesz;
447 ds_shdr->sh_type = SHT_PROGBITS;
448 ds_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
449 ds_shdr->sh_offset = oe->phdr[I_DS].p_offset;
450 ds_shdr->sh_addr = oe->phdr[I_DS].p_vaddr;
451 ds_shdr->sh_addralign = oe->phdr[I_DS].p_align;
452 ds_shdr->sh_size = oe->phdr[I_DS].p_filesz;
454 bss_shdr->sh_type = SHT_NOBITS;
455 bss_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
456 bss_shdr->sh_offset = oe->phdr[I_BSS].p_offset;
457 bss_shdr->sh_addr = oe->phdr[I_BSS].p_vaddr;
458 bss_shdr->sh_addralign = oe->phdr[I_BSS].p_align;
459 bss_shdr->sh_size = oe->phdr[I_BSS].p_filesz;
462 static void outelf_write(struct outelf *oe, int fd)
464 int i;
465 oe->ehdr.e_entry = outelf_addr(oe, entry) -
466 sec_vaddr[I_CS] + sec_laddr[I_CS];
467 if (!nosyms)
468 build_symtab(oe);
469 oe->ehdr.e_phnum = oe->nph;
470 oe->ehdr.e_phoff = sizeof(oe->ehdr);
471 oe->ehdr.e_machine = e_machine;
472 oe->ehdr.e_flags = e_flags;
473 lseek(fd, 0, SEEK_SET);
474 write(fd, &oe->ehdr, sizeof(oe->ehdr));
475 write(fd, &oe->phdr, oe->nph * sizeof(oe->phdr[0]));
476 for (i = 0; i < oe->nsecs; i++) {
477 struct secmap *sec = &oe->secs[i];
478 char *buf = sec->obj->mem + sec->o_shdr->sh_offset;
479 int len = sec->o_shdr->sh_size;
480 if (SEC_BSS(sec->o_shdr))
481 continue;
482 lseek(fd, sec->faddr, SEEK_SET);
483 write(fd, buf, len);
485 if (!nosyms) {
486 lseek(fd, oe->shdr_faddr, SEEK_SET);
487 write(fd, &oe->shdr, oe->nsh * sizeof(oe->shdr[0]));
488 lseek(fd, oe->syms_faddr, SEEK_SET);
489 write(fd, &oe->syms, oe->nsyms * sizeof(oe->syms[0]));
490 lseek(fd, oe->symstr_faddr, SEEK_SET);
491 write(fd, &oe->symstr, oe->nsymstr);
495 static void outelf_add(struct outelf *oe, char *mem)
497 Elf_Ehdr *ehdr = (void *) mem;
498 Elf_Shdr *shdr = (void *) (mem + ehdr->e_shoff);
499 struct obj *obj;
500 int i;
501 if (ehdr->e_type != ET_REL)
502 return;
503 e_machine = ehdr->e_machine;
504 e_flags = ehdr->e_flags;
505 if (oe->nobjs >= MAXOBJS)
506 die("neatld: MAXOBJS reached!");
507 obj = &oe->objs[oe->nobjs++];
508 obj_init(obj, mem);
509 for (i = 0; i < ehdr->e_shnum; i++) {
510 struct secmap *sec;
511 if (!(shdr[i].sh_flags & 0x7))
512 continue;
513 if (oe->nsecs >= MAXSECS)
514 die("neatld: MAXSECS reached!");
515 sec = &oe->secs[oe->nsecs++];
516 sec->o_shdr = &shdr[i];
517 sec->obj = obj;
521 static int link_cs(struct outelf *oe, Elf_Phdr *phdr, unsigned long faddr,
522 unsigned long vaddr, unsigned long laddr, int len)
524 int i;
525 for (i = 0; i < oe->nsecs; i++) {
526 struct secmap *sec = &oe->secs[i];
527 int alignment = MAX(sec->o_shdr->sh_addralign, 4);
528 if (!SEC_CODE(sec->o_shdr))
529 continue;
530 len = ALIGN(vaddr + len, alignment) - vaddr;
531 sec->vaddr = vaddr + len;
532 sec->faddr = faddr + len;
533 len += sec->o_shdr->sh_size;
535 phdr->p_type = PT_LOAD;
536 phdr->p_flags = PF_R | PF_X;
537 phdr->p_vaddr = vaddr;
538 phdr->p_paddr = laddr;
539 phdr->p_offset = faddr;
540 phdr->p_filesz = len;
541 phdr->p_memsz = len;
542 phdr->p_align = PAGE_SIZE;
543 return len;
546 static int link_ds(struct outelf *oe, Elf_Phdr *phdr, unsigned long faddr,
547 unsigned long vaddr, unsigned long laddr)
549 int len = 0;
550 int i;
551 for (i = 0; i < oe->nsecs; i++) {
552 struct secmap *sec = &oe->secs[i];
553 if (!SEC_DATA(sec->o_shdr))
554 continue;
555 sec->vaddr = vaddr + len;
556 sec->faddr = faddr + len;
557 len += sec->o_shdr->sh_size;
559 len = ALIGN(len, 4);
560 phdr->p_type = PT_LOAD;
561 phdr->p_flags = PF_R | PF_W;
562 phdr->p_align = PAGE_SIZE;
563 phdr->p_vaddr = vaddr;
564 phdr->p_paddr = laddr;
565 phdr->p_filesz = len;
566 phdr->p_memsz = len;
567 phdr->p_offset = faddr;
568 return len;
571 static int link_bss(struct outelf *oe, Elf_Phdr *phdr,
572 unsigned long faddr, unsigned long vaddr, int len)
574 int i;
575 for (i = 0; i < oe->nsecs; i++) {
576 struct secmap *sec = &oe->secs[i];
577 int alignment = MAX(sec->o_shdr->sh_addralign, 4);
578 if (!SEC_BSS(sec->o_shdr))
579 continue;
580 len = ALIGN(vaddr + len, alignment) - vaddr;
581 sec->vaddr = vaddr + len;
582 sec->faddr = faddr;
583 len += sec->o_shdr->sh_size;
585 phdr->p_type = PT_LOAD;
586 phdr->p_flags = PF_R | PF_W;
587 phdr->p_vaddr = vaddr;
588 phdr->p_paddr = vaddr;
589 phdr->p_offset = faddr;
590 phdr->p_filesz = 0;
591 phdr->p_memsz = len;
592 phdr->p_align = PAGE_SIZE;
593 return len;
596 static void outelf_link(struct outelf *oe)
598 unsigned long faddr, vaddr, laddr;
599 int len;
600 len = ALIGN(sizeof(oe->ehdr) + MAXPHDRS * sizeof(oe->phdr[0]), secalign);
601 faddr = len & ~PAGE_MASK;
602 vaddr = sec_vaddr[I_CS];
603 laddr = sec_laddr[I_CS];
604 len = link_cs(oe, &oe->phdr[0], faddr, vaddr, laddr, len & PAGE_MASK);
606 len = ALIGN(faddr + len, secalign) - faddr;
607 faddr += len;
608 vaddr = sec_set[I_DS] ? sec_vaddr[I_DS] | (faddr & PAGE_MASK) :
609 vaddr + PAGE_SIZE + len;
610 laddr = sec_set[I_DS] ? sec_laddr[I_DS] | (faddr & PAGE_MASK) :
611 laddr + PAGE_SIZE + len;
612 len = link_ds(oe, &oe->phdr[1], faddr, vaddr, laddr);
614 len = ALIGN(faddr + len, secalign) - faddr;
615 faddr += len;
616 vaddr = sec_set[I_BSS] ? sec_vaddr[I_BSS] | (faddr & PAGE_MASK) :
617 vaddr + PAGE_SIZE + len;
618 outelf_bss(oe);
619 oe->bss_vaddr = vaddr;
620 len = link_bss(oe, &oe->phdr[2], faddr, vaddr, oe->bss_len);
622 oe->nph = 3;
623 outelf_reloc(oe);
624 oe->shdr_faddr = faddr;
627 struct arhdr {
628 char ar_name[16];
629 char ar_date[12];
630 char ar_uid[6];
631 char ar_gid[6];
632 char ar_mode[8];
633 char ar_size[10];
634 char ar_fmag[2];
637 static int get_be32(unsigned char *s)
639 return s[3] | (s[2] << 8) | (s[1] << 16) | (s[0] << 24);
642 static int sym_undef(struct outelf *oe, char *name)
644 int i, j;
645 int undef = 0;
646 for (i = 0; i < oe->nobjs; i++) {
647 struct obj *obj = &oe->objs[i];
648 for (j = 0; j < obj->nsyms; j++) {
649 Elf_Sym *sym = &obj->syms[j];
650 if (ELF_ST_BIND(sym->st_info) == STB_LOCAL)
651 continue;
652 if (strcmp(name, obj->symstr + sym->st_name))
653 continue;
654 if (sym->st_shndx != SHN_UNDEF)
655 return 0;
656 undef = 1;
659 return undef;
662 static int outelf_ar_link(struct outelf *oe, char *ar, int base)
664 char *ar_index;
665 char *ar_name;
666 int nsyms = get_be32((void *) ar);
667 int added = 0;
668 int i;
669 ar_index = ar + 4;
670 ar_name = ar_index + nsyms * 4;
671 for (i = 0; i < nsyms; i++) {
672 int off = get_be32((void *) ar_index + i * 4) +
673 sizeof(struct arhdr);
674 if (sym_undef(oe, ar_name)) {
675 outelf_add(oe, ar - base + off);
676 added++;
678 ar_name = strchr(ar_name, '\0') + 1;
680 return added;
683 static void outelf_archive(struct outelf *oe, char *ar)
685 char *beg = ar;
687 /* skip magic */
688 ar += 8;
689 for(;;) {
690 struct arhdr *hdr = (void *) ar;
691 char *name = hdr->ar_name;
692 int size;
693 ar += sizeof(*hdr);
694 hdr->ar_size[sizeof(hdr->ar_size) - 1] = '\0';
695 size = atoi(hdr->ar_size);
696 size = (size + 1) & ~1;
697 if (name[0] == '/' && name[1] == ' ') {
698 while (outelf_ar_link(oe, ar, ar - beg))
700 return;
702 if (name[0] == '/' && name[1] == '/' && name[2] == ' ')
703 outelf_add(oe, ar);
704 ar += size;
708 static long filesize(int fd)
710 struct stat stat;
711 fstat(fd, &stat);
712 return stat.st_size;
715 static char *fileread(char *path)
717 int fd = open(path, O_RDONLY);
718 int size = filesize(fd);
719 char *buf = malloc(size);
720 read(fd, buf, size);
721 close(fd);
722 return buf;
725 static int is_ar(char *path)
727 int len = strlen(path);
728 return len > 2 && path[len - 2] == '.' && path[len - 1] == 'a';
731 #define LIBDIRS (1 << 5)
732 #define PATHLEN (1 << 8)
734 static char *libdirs[LIBDIRS] = {"/lib"};
735 static int nlibdirs = 1;
737 static int lib_find(char *path, char *lib)
739 struct stat st;
740 int i;
741 for (i = 0; i < nlibdirs; i++) {
742 sprintf(path, "%s/lib%s.a", libdirs[i], lib);
743 if (!stat(path, &st))
744 return 0;
746 return 1;
749 static unsigned long hexnum(char *s)
751 unsigned long n = 0;
752 if (s[0] == '0' && s[1] == 'x')
753 s += 2;
754 for (; isdigit(*s) || isalpha(*s); s++) {
755 n <<= 4;
756 n |= isdigit(*s) ? *s - '0' : tolower(*s) - 'a' + 10;
758 return n;
761 static void set_addr(int sec, char *arg)
763 int idx = I_CS;
764 char *sep = strchr(arg, ':');
765 if (sec == 'd')
766 idx = I_DS;
767 if (sec == 'b')
768 idx = I_BSS;
769 sec_vaddr[idx] = hexnum(arg);
770 sec_laddr[idx] = sep ? hexnum(sep + 1) : sec_vaddr[idx];
771 sec_set[idx] = 1;
774 static char *obj_add(struct outelf *oe, char *path)
776 char *buf = fileread(path);
777 if (!buf)
778 die("neatld: cannot open object!");
779 if (is_ar(path))
780 outelf_archive(oe, buf);
781 else
782 outelf_add(oe, buf);
783 return buf;
786 int main(int argc, char **argv)
788 char out[PATHLEN] = "a.out";
789 struct outelf oe;
790 char *mem[MAXFILES];
791 int nmem = 0;
792 int fd;
793 int i = 0;
794 if (argc < 2)
795 die("neatld: no object given!");
796 outelf_init(&oe);
798 while (++i < argc) {
799 if (argv[i][0] != '-') {
800 mem[nmem++] = obj_add(&oe, argv[i]);
801 continue;
803 if (argv[i][1] == 'l') {
804 char path[PATHLEN];
805 if (lib_find(path, argv[i] + 2))
806 die("neatld: cannot find library!");
807 mem[nmem++] = obj_add(&oe, path);
808 continue;
810 if (argv[i][1] == 'L') {
811 libdirs[nlibdirs++] = argv[i][2] ? argv[i] + 2 : argv[++i];
812 continue;
814 if (argv[i][1] == 'o') {
815 strcpy(out, argv[i][2] ? argv[i] + 2 : argv[++i]);
816 continue;
818 if (argv[i][1] == 's') {
819 nosyms = 1;
820 continue;
822 if (argv[i][1] == 'g')
823 continue;
824 if (argv[i][1] == 'm') {
825 char sec = argv[i][2];
826 char *arg = argv[i][3] == '=' ? argv[i] + 4 : argv[++i];
827 set_addr(sec, arg);
828 continue;
830 if (argv[i][1] == 'p') {
831 secalign = PAGE_SIZE;
832 continue;
834 if (argv[i][1] == 'e') {
835 entry = argv[i][2] ? argv[i] + 2 : argv[++i];
836 continue;
838 if (argv[i][1] == 'h') {
839 printf("Usage: neatld [options] objects\n\n");
840 printf("Options:\n");
841 printf(" -o out set the output file\n");
842 printf(" -l lib link with library lib\n");
843 printf(" -L dir search dir for libraries\n");
844 printf(" -s do not include a symbol table\n");
845 printf(" -mXvaddr:laddr section virtual/load address\n");
846 printf(" -p page-align sections\n");
847 printf(" -e entry point symbol\n");
848 return 1;
851 outelf_link(&oe);
852 fd = open(out, O_WRONLY | O_TRUNC | O_CREAT, 0700);
853 if (fd < 0)
854 die("neatld: failed to create the output!");
855 outelf_write(&oe, fd);
856 close(fd);
857 for (i = 0; i < nmem; i++)
858 free(mem[i]);
859 return 0;