add -s to strip the symbol table
[ld.git] / ld.c
blobeb4efb6da8049aa4b2e95654199b562b0302fbbb
1 /*
2 * ld - a small static linker
4 * Copyright (C) 2010-2011 Ali Gholami Rudi
6 * This program is released under GNU GPL version 2.
7 */
8 #include <elf.h>
9 #include <fcntl.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <sys/stat.h>
13 #include <string.h>
14 #include <unistd.h>
16 #define SRCADDR 0x4000000ul
17 #define DATADDR 0x6000000ul
18 #define BSSADDR 0x8000000ul
19 #define SECALIGN (1 << 2)
20 #define MAXSECS (1 << 10)
21 #define MAXOBJS (1 << 7)
22 #define MAXSYMS (1 << 12)
23 #define PAGE_SIZE (1 << 12)
24 #define MAXFILES (1 << 10)
25 #define MAXPHDRS 4
27 #define MAX(a, b) ((a) > (b) ? (a) : (b))
28 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
30 struct obj {
31 char *mem;
32 Elf32_Ehdr *ehdr;
33 Elf32_Shdr *shdr;
34 Elf32_Sym *syms;
35 int nsyms;
36 char *symstr;
37 char *shstr;
40 struct secmap {
41 Elf32_Shdr *o_shdr;
42 struct obj *obj;
43 unsigned long vaddr;
44 unsigned long faddr;
47 struct bss_sym {
48 Elf32_Sym *sym;
49 int off;
52 struct outelf {
53 Elf32_Ehdr ehdr;
54 Elf32_Phdr phdr[MAXSECS];
55 int nph;
56 struct secmap secs[MAXSECS];
57 int nsecs;
58 struct obj objs[MAXOBJS];
59 int nobjs;
61 /* code section */
62 unsigned long code_addr;
64 /* bss section */
65 struct bss_sym bss_syms[MAXSYMS];
66 int nbss_syms;
67 unsigned long bss_vaddr;
68 int bss_len;
70 /* symtab section */
71 Elf32_Shdr shdr[MAXSECS];
72 int nsh;
73 char symstr[MAXSYMS];
74 Elf32_Sym syms[MAXSYMS];
75 int nsyms;
76 int nsymstr;
77 unsigned long shdr_faddr;
78 unsigned long syms_faddr;
79 unsigned long symstr_faddr;
82 static int nosyms = 0;
84 static Elf32_Sym *obj_find(struct obj *obj, char *name)
86 int i;
87 for (i = 0; i < obj->nsyms; i++) {
88 Elf32_Sym *sym = &obj->syms[i];
89 if (ELF32_ST_BIND(sym->st_info) == STB_LOCAL ||
90 sym->st_shndx == SHN_UNDEF)
91 continue;
92 if (!strcmp(name, obj->symstr + sym->st_name))
93 return sym;
95 return NULL;
98 static void obj_init(struct obj *obj, char *mem)
100 int i;
101 obj->mem = mem;
102 obj->ehdr = (void *) mem;
103 obj->shdr = (void *) (mem + obj->ehdr->e_shoff);
104 obj->shstr = mem + obj->shdr[obj->ehdr->e_shstrndx].sh_offset;
105 for (i = 0; i < obj->ehdr->e_shnum; i++) {
106 if (obj->shdr[i].sh_type != SHT_SYMTAB)
107 continue;
108 obj->symstr = mem + obj->shdr[obj->shdr[i].sh_link].sh_offset;
109 obj->syms = (void *) (mem + obj->shdr[i].sh_offset);
110 obj->nsyms = obj->shdr[i].sh_size / sizeof(*obj->syms);
114 static void outelf_init(struct outelf *oe)
116 memset(oe, 0, sizeof(*oe));
117 oe->ehdr.e_ident[0] = 0x7f;
118 oe->ehdr.e_ident[1] = 'E';
119 oe->ehdr.e_ident[2] = 'L';
120 oe->ehdr.e_ident[3] = 'F';
121 oe->ehdr.e_ident[4] = ELFCLASS32;
122 oe->ehdr.e_ident[5] = ELFDATA2LSB;
123 oe->ehdr.e_ident[6] = EV_CURRENT;
124 oe->ehdr.e_type = ET_EXEC;
125 oe->ehdr.e_machine = EM_386;
126 oe->ehdr.e_version = EV_CURRENT;
127 oe->ehdr.e_shstrndx = SHN_UNDEF;
128 oe->ehdr.e_ehsize = sizeof(oe->ehdr);
129 oe->ehdr.e_phentsize = sizeof(oe->phdr[0]);
130 oe->ehdr.e_shentsize = sizeof(Elf32_Shdr);
133 static struct secmap *outelf_mapping(struct outelf *oe, Elf32_Shdr *shdr)
135 int i;
136 for (i = 0; i < oe->nsecs; i++)
137 if (oe->secs[i].o_shdr == shdr)
138 return &oe->secs[i];
139 return NULL;
142 static int outelf_find(struct outelf *oe, char *name,
143 struct obj **sym_obj, Elf32_Sym **sym_sym)
145 int i;
146 for (i = 0; i < oe->nobjs; i++) {
147 struct obj *obj = &oe->objs[i];
148 Elf32_Sym *sym;
149 if ((sym = obj_find(obj, name))) {
150 *sym_obj = obj;
151 *sym_sym = sym;
152 return 0;
155 return 1;
158 static unsigned long bss_addr(struct outelf *oe, Elf32_Sym *sym)
160 int i;
161 for (i = 0; i < oe->nbss_syms; i++)
162 if (oe->bss_syms[i].sym == sym)
163 return oe->bss_vaddr + oe->bss_syms[i].off;
164 return 0;
167 static void die(char *msg)
169 write(1, msg, strlen(msg));
170 exit(1);
173 static void warn_undef(char *name)
175 char msg[128];
176 strcpy(msg, name);
177 strcpy(msg + strlen(msg), " undefined\n");
178 die(msg);
181 static unsigned long symval(struct outelf *oe, struct obj *obj, Elf32_Sym *sym)
183 struct secmap *sec;
184 char *name = obj ? obj->symstr + sym->st_name : NULL;
185 int s_idx, s_off;
186 switch (ELF32_ST_TYPE(sym->st_info)) {
187 case STT_SECTION:
188 if ((sec = outelf_mapping(oe, &obj->shdr[sym->st_shndx])))
189 return sec->vaddr;
190 break;
191 case STT_NOTYPE:
192 case STT_OBJECT:
193 case STT_FUNC:
194 if (name && *name && sym->st_shndx == SHN_UNDEF)
195 if (outelf_find(oe, name, &obj, &sym))
196 warn_undef(name);
197 if (sym->st_shndx == SHN_COMMON)
198 return bss_addr(oe, sym);
199 s_idx = sym->st_shndx;
200 s_off = sym->st_value;
201 sec = outelf_mapping(oe, &obj->shdr[s_idx]);
202 if ((sec = outelf_mapping(oe, &obj->shdr[s_idx])))
203 return sec->vaddr + s_off;
205 return 0;
208 static unsigned long outelf_addr(struct outelf *oe, char *name)
210 struct obj *obj;
211 Elf32_Sym *sym;
212 if (outelf_find(oe, name, &obj, &sym))
213 die("unknown symbol!\n");
214 return symval(oe, obj, sym);
217 static void outelf_reloc_sec(struct outelf *oe, int o_idx, int s_idx)
219 struct obj *obj = &oe->objs[o_idx];
220 Elf32_Shdr *rel_shdr = &obj->shdr[s_idx];
221 Elf32_Rel *rels = (void *) obj->mem + obj->shdr[s_idx].sh_offset;
222 Elf32_Shdr *other_shdr = &obj->shdr[rel_shdr->sh_info];
223 void *other = (void *) obj->mem + other_shdr->sh_offset;
224 int nrels = rel_shdr->sh_size / sizeof(*rels);
225 unsigned long addr;
226 int i;
227 for (i = 0; i < nrels; i++) {
228 Elf32_Rela *rel = (void *) &rels[i];
229 int sym_idx = ELF32_R_SYM(rel->r_info);
230 Elf32_Sym *sym = &obj->syms[sym_idx];
231 unsigned long val = symval(oe, obj, sym);
232 unsigned long *dst = other + rel->r_offset;
233 switch (ELF32_R_TYPE(rel->r_info)) {
234 case R_386_NONE:
235 break;
236 case R_386_16:
237 *(unsigned short *) dst += val;
238 break;
239 case R_386_32:
240 *dst += val;
241 break;
242 case R_386_PC32:
243 case R_386_PLT32:
244 addr = outelf_mapping(oe, other_shdr)->vaddr +
245 rel->r_offset;
246 *dst += val - addr;
247 break;
248 default:
249 die("unknown relocation type\n");
254 static void outelf_reloc(struct outelf *oe)
256 int i, j;
257 for (i = 0; i < oe->nobjs; i++) {
258 struct obj *obj = &oe->objs[i];
259 for (j = 0; j < obj->ehdr->e_shnum; j++)
260 if (obj->shdr[j].sh_type == SHT_REL)
261 outelf_reloc_sec(oe, i, j);
265 static void alloc_bss(struct outelf *oe, Elf32_Sym *sym)
267 int n = oe->nbss_syms++;
268 int off = ALIGN(oe->bss_len, MAX(sym->st_value, 4));
269 oe->bss_syms[n].sym = sym;
270 oe->bss_syms[n].off = off;
271 oe->bss_len = off + sym->st_size;
274 static void outelf_bss(struct outelf *oe)
276 int i, j;
277 for (i = 0; i < oe->nobjs; i++) {
278 struct obj *obj = &oe->objs[i];
279 for (j = 0; j < obj->nsyms; j++)
280 if (obj->syms[j].st_shndx == SHN_COMMON)
281 alloc_bss(oe, &obj->syms[j]);
285 #define SEC_CODE(s) ((s)->sh_flags & SHF_EXECINSTR)
286 #define SEC_BSS(s) ((s)->sh_type == SHT_NOBITS)
287 #define SEC_DATA(s) (!SEC_CODE(s) && !SEC_BSS(s))
289 static char *putstr(char *d, char *s)
291 while (*s)
292 *d++ = *s++;
293 *d++ = '\0';
294 return d;
297 static void build_symtab(struct outelf *oe)
299 int i, j;
300 char *symstr = oe->symstr;
301 Elf32_Sym *syms = oe->syms;
302 Elf32_Shdr *sym_shdr = &oe->shdr[1];
303 Elf32_Shdr *str_shdr = &oe->shdr[2];
304 int n = 1;
305 char *s = putstr(symstr, "");
306 int faddr = oe->shdr_faddr;
307 oe->nsh = 3;
308 for (i = 0; i < oe->nobjs; i++) {
309 struct obj *obj = &oe->objs[i];
310 for (j = 0; j < obj->nsyms; j++) {
311 Elf32_Sym *sym = &obj->syms[j];
312 int type = ELF32_ST_TYPE(sym->st_info);
313 int bind = ELF32_ST_BIND(sym->st_info);
314 char *name = obj->symstr + sym->st_name;
315 if (!*name || bind == STB_LOCAL ||
316 sym->st_shndx == SHN_UNDEF)
317 continue;
318 syms[n].st_name = s - symstr;
319 s = putstr(s, name);
320 syms[n].st_info = ELF32_ST_INFO(bind, type);
321 syms[n].st_value = symval(oe, obj, sym);
322 syms[n].st_size = sym->st_size;
323 syms[n].st_shndx = SHN_ABS;
324 n++;
327 oe->nsymstr = s - symstr;
328 oe->nsyms = n;
330 oe->shdr_faddr = faddr;
331 faddr += oe->nsh * sizeof(oe->shdr[0]);
332 oe->syms_faddr = faddr;
333 faddr += oe->nsyms * sizeof(oe->syms[0]);
334 oe->symstr_faddr = faddr;
335 faddr += oe->nsymstr;
337 oe->ehdr.e_shstrndx = str_shdr - oe->shdr;
338 oe->ehdr.e_shoff = oe->shdr_faddr;
339 oe->ehdr.e_shnum = oe->nsh;
341 str_shdr->sh_name = 0;
342 str_shdr->sh_type = SHT_STRTAB;
343 str_shdr->sh_offset = oe->symstr_faddr;
344 str_shdr->sh_size = oe->nsymstr;
346 sym_shdr->sh_name = 0;
347 sym_shdr->sh_type = SHT_SYMTAB;
348 sym_shdr->sh_entsize = sizeof(oe->syms[0]);
349 sym_shdr->sh_offset = oe->syms_faddr;
350 sym_shdr->sh_size = oe->nsyms * sizeof(oe->syms[0]);
351 sym_shdr->sh_link = str_shdr - oe->shdr;
352 sym_shdr->sh_info = 0;
355 static void outelf_write(struct outelf *oe, int fd)
357 int i;
358 oe->ehdr.e_entry = outelf_addr(oe, "_start");
359 if (!nosyms)
360 build_symtab(oe);
361 oe->ehdr.e_phnum = oe->nph;
362 oe->ehdr.e_phoff = sizeof(oe->ehdr);
363 lseek(fd, 0, SEEK_SET);
364 write(fd, &oe->ehdr, sizeof(oe->ehdr));
365 write(fd, &oe->phdr, oe->nph * sizeof(oe->phdr[0]));
366 for (i = 0; i < oe->nsecs; i++) {
367 struct secmap *sec = &oe->secs[i];
368 char *buf = sec->obj->mem + sec->o_shdr->sh_offset;
369 int len = sec->o_shdr->sh_size;
370 if (SEC_BSS(sec->o_shdr))
371 continue;
372 lseek(fd, sec->faddr, SEEK_SET);
373 write(fd, buf, len);
375 if (!nosyms) {
376 lseek(fd, oe->shdr_faddr, SEEK_SET);
377 write(fd, &oe->shdr, oe->nsh * sizeof(oe->shdr[0]));
378 lseek(fd, oe->syms_faddr, SEEK_SET);
379 write(fd, &oe->syms, oe->nsyms * sizeof(oe->syms[0]));
380 lseek(fd, oe->symstr_faddr, SEEK_SET);
381 write(fd, &oe->symstr, oe->nsymstr);
385 static void outelf_add(struct outelf *oe, char *mem)
387 Elf32_Ehdr *ehdr = (void *) mem;
388 Elf32_Shdr *shdr = (void *) (mem + ehdr->e_shoff);
389 struct obj *obj;
390 int i;
391 if (ehdr->e_type != ET_REL)
392 return;
393 if (oe->nobjs >= MAXOBJS)
394 die("ld: MAXOBJS reached!\n");
395 obj = &oe->objs[oe->nobjs++];
396 obj_init(obj, mem);
397 for (i = 0; i < ehdr->e_shnum; i++) {
398 struct secmap *sec;
399 if (!(shdr[i].sh_flags & 0x7))
400 continue;
401 if (oe->nsecs >= MAXSECS)
402 die("ld: MAXSECS reached\n");
403 sec = &oe->secs[oe->nsecs++];
404 sec->o_shdr = &shdr[i];
405 sec->obj = obj;
409 static void outelf_link(struct outelf *oe)
411 int i;
412 Elf32_Phdr *code_phdr = &oe->phdr[oe->nph++];
413 Elf32_Phdr *data_phdr = &oe->phdr[oe->nph++];
414 Elf32_Phdr *bss_phdr = &oe->phdr[oe->nph++];
415 unsigned long faddr = sizeof(oe->ehdr) + MAXPHDRS * sizeof(oe->phdr[0]);
416 unsigned long vaddr;
417 int len = 0;
418 faddr = ALIGN(faddr, SECALIGN);
419 vaddr = SRCADDR + faddr % PAGE_SIZE;
420 for (i = 0; i < oe->nsecs; i++) {
421 struct secmap *sec = &oe->secs[i];
422 int alignment = MAX(sec->o_shdr->sh_addralign, 4);
423 if (!SEC_CODE(sec->o_shdr))
424 continue;
425 len = ALIGN(vaddr + len, alignment) - vaddr;
426 sec->vaddr = vaddr + len;
427 sec->faddr = faddr + len;
428 len += sec->o_shdr->sh_size;
430 code_phdr->p_type = PT_LOAD;
431 code_phdr->p_flags = PF_R | PF_W | PF_X;
432 code_phdr->p_vaddr = vaddr - faddr;
433 code_phdr->p_paddr = vaddr - faddr;
434 code_phdr->p_offset = faddr - faddr;
435 code_phdr->p_filesz = len + faddr;
436 code_phdr->p_memsz = len + faddr;
437 code_phdr->p_align = PAGE_SIZE;
439 len = ALIGN(faddr + len, SECALIGN) - faddr;
440 faddr += len;
441 vaddr = DATADDR ? DATADDR + faddr % PAGE_SIZE : vaddr + len;
442 len = 0;
443 for (i = 0; i < oe->nsecs; i++) {
444 struct secmap *sec = &oe->secs[i];
445 if (!SEC_DATA(sec->o_shdr))
446 continue;
447 sec->vaddr = vaddr + len;
448 sec->faddr = faddr + len;
449 len += sec->o_shdr->sh_size;
451 len = ALIGN(len, 4);
452 data_phdr->p_type = PT_LOAD;
453 data_phdr->p_flags = PF_R | PF_W | PF_X;
454 data_phdr->p_align = PAGE_SIZE;
455 data_phdr->p_vaddr = vaddr;
456 data_phdr->p_paddr = vaddr;
457 data_phdr->p_filesz = len;
458 data_phdr->p_memsz = len;
459 data_phdr->p_offset = faddr;
461 len = ALIGN(faddr + len, SECALIGN) - faddr;
462 faddr += len;
463 vaddr = BSSADDR ? BSSADDR + faddr % PAGE_SIZE : vaddr + len;
464 len = 0;
465 outelf_bss(oe);
466 oe->bss_vaddr = vaddr + len;
467 len += oe->bss_len;
468 for (i = 0; i < oe->nsecs; i++) {
469 struct secmap *sec = &oe->secs[i];
470 int alignment = MAX(sec->o_shdr->sh_addralign, 4);
471 if (!SEC_BSS(sec->o_shdr))
472 continue;
473 len = ALIGN(vaddr + len, alignment) - vaddr;
474 sec->vaddr = vaddr + len;
475 sec->faddr = faddr;
476 len += sec->o_shdr->sh_size;
478 bss_phdr->p_type = PT_LOAD;
479 bss_phdr->p_flags = PF_R | PF_W;
480 bss_phdr->p_vaddr = vaddr;
481 bss_phdr->p_paddr = vaddr;
482 bss_phdr->p_offset = faddr;
483 bss_phdr->p_filesz = 0;
484 bss_phdr->p_memsz = len;
485 bss_phdr->p_align = PAGE_SIZE;
487 outelf_reloc(oe);
488 oe->shdr_faddr = faddr;
491 struct arhdr {
492 char ar_name[16];
493 char ar_date[12];
494 char ar_uid[6];
495 char ar_gid[6];
496 char ar_mode[8];
497 char ar_size[10];
498 char ar_fmag[2];
501 static int get_be32(unsigned char *s)
503 return s[3] | (s[2] << 8) | (s[1] << 16) | (s[0] << 24);
506 static int sym_undef(struct outelf *oe, char *name)
508 int i, j;
509 int undef = 0;
510 for (i = 0; i < oe->nobjs; i++) {
511 struct obj *obj = &oe->objs[i];
512 for (j = 0; j < obj->nsyms; j++) {
513 Elf32_Sym *sym = &obj->syms[j];
514 if (ELF32_ST_BIND(sym->st_info) == STB_LOCAL)
515 continue;
516 if (strcmp(name, obj->symstr + sym->st_name))
517 continue;
518 if (sym->st_shndx != SHN_UNDEF)
519 return 0;
520 undef = 1;
523 return undef;
526 static int outelf_ar_link(struct outelf *oe, char *ar, int base)
528 char *ar_index;
529 char *ar_name;
530 int nsyms = get_be32((void *) ar);
531 int added = 0;
532 int i;
533 ar_index = ar + 4;
534 ar_name = ar_index + nsyms * 4;
535 for (i = 0; i < nsyms; i++) {
536 int off = get_be32((void *) ar_index + i * 4) +
537 sizeof(struct arhdr);
538 if (sym_undef(oe, ar_name)) {
539 outelf_add(oe, ar - base + off);
540 added++;
542 ar_name = strchr(ar_name, '\0') + 1;
544 return added;
547 static void link_archive(struct outelf *oe, char *ar)
549 char *beg = ar;
551 /* skip magic */
552 ar += 8;
553 for(;;) {
554 struct arhdr *hdr = (void *) ar;
555 int size;
556 ar += sizeof(*hdr);
557 hdr->ar_size[sizeof(hdr->ar_size) - 1] = '\0';
558 size = atoi(hdr->ar_size);
559 size = (size + 1) & ~1;
560 if (!strncmp(hdr->ar_name, "/ ", 2)) {
561 while (outelf_ar_link(oe, ar, ar - beg))
563 return;
565 if (!strncmp(hdr->ar_name, "// ", 3))
566 outelf_add(oe, ar);
567 ar += size;
571 static long filesize(int fd)
573 struct stat stat;
574 fstat(fd, &stat);
575 return stat.st_size;
578 static char *fileread(char *path)
580 int fd = open(path, O_RDONLY);
581 int size = filesize(fd);
582 char *buf = malloc(size);
583 read(fd, buf, size);
584 close(fd);
585 return buf;
588 static int is_ar(char *path)
590 int len = strlen(path);
591 return len > 2 && path[len - 2] == '.' && path[len - 1] == 'a';
594 int main(int argc, char **argv)
596 char out[1 << 10] = "a.out";
597 char *buf;
598 struct outelf oe;
599 char *mem[MAXFILES];
600 int nmem = 0;
601 int fd;
602 int i = 0;
603 if (argc < 2)
604 die("no object given\n");
605 outelf_init(&oe);
607 while (++i < argc) {
608 if (!strcmp("-o", argv[i])) {
609 strcpy(out, argv[++i]);
610 continue;
612 if (!strcmp("-s", argv[i])) {
613 nosyms = 1;
614 continue;
616 if (!strcmp("-g", argv[i]))
617 continue;
618 buf = fileread(argv[i]);
619 mem[nmem++] = buf;
620 if (!buf)
621 die("cannot open object\n");
622 if (is_ar(argv[i]))
623 link_archive(&oe, buf);
624 else
625 outelf_add(&oe, buf);
627 outelf_link(&oe);
628 fd = open(out, O_WRONLY | O_TRUNC | O_CREAT, 0700);
629 outelf_write(&oe, fd);
630 close(fd);
631 for (i = 0; i < nmem; i++)
632 free(mem[i]);
633 return 0;