2 * ld - a small static linker
4 * Copyright (C) 2010-2011 Ali Gholami Rudi
6 * This program is released under GNU GPL version 2.
21 static unsigned long sec_vaddr
[3] = {0x800000}; /* virtual address of sections */
22 static unsigned long sec_laddr
[3] = {0x800000}; /* load address of sections */
23 static int sec_set
[3] = {1}; /* set address for section */
24 static int secalign
= 16; /* section alignment */
25 static char *entry
= "_start"; /* entry symbol */
27 #define MAXSECS (1 << 10)
28 #define MAXOBJS (1 << 7)
29 #define MAXSYMS (1 << 12)
30 #define PAGE_SIZE (1 << 12)
31 #define PAGE_MASK (PAGE_SIZE - 1)
32 #define MAXFILES (1 << 10)
35 #define MAX(a, b) ((a) > (b) ? (a) : (b))
36 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
62 Elf32_Phdr phdr
[MAXSECS
];
64 struct secmap secs
[MAXSECS
];
66 struct obj objs
[MAXOBJS
];
70 unsigned long code_addr
;
73 struct bss_sym bss_syms
[MAXSYMS
];
75 unsigned long bss_vaddr
;
79 Elf32_Shdr shdr
[MAXSECS
];
82 Elf32_Sym syms
[MAXSYMS
];
85 unsigned long shdr_faddr
;
86 unsigned long syms_faddr
;
87 unsigned long symstr_faddr
;
90 static int nosyms
= 0;
92 static Elf32_Sym
*obj_find(struct obj
*obj
, char *name
)
95 for (i
= 0; i
< obj
->nsyms
; i
++) {
96 Elf32_Sym
*sym
= &obj
->syms
[i
];
97 if (ELF32_ST_BIND(sym
->st_info
) == STB_LOCAL
||
98 sym
->st_shndx
== SHN_UNDEF
)
100 if (!strcmp(name
, obj
->symstr
+ sym
->st_name
))
106 static void obj_init(struct obj
*obj
, char *mem
)
110 obj
->ehdr
= (void *) mem
;
111 obj
->shdr
= (void *) (mem
+ obj
->ehdr
->e_shoff
);
112 obj
->shstr
= mem
+ obj
->shdr
[obj
->ehdr
->e_shstrndx
].sh_offset
;
113 for (i
= 0; i
< obj
->ehdr
->e_shnum
; i
++) {
114 if (obj
->shdr
[i
].sh_type
!= SHT_SYMTAB
)
116 obj
->symstr
= mem
+ obj
->shdr
[obj
->shdr
[i
].sh_link
].sh_offset
;
117 obj
->syms
= (void *) (mem
+ obj
->shdr
[i
].sh_offset
);
118 obj
->nsyms
= obj
->shdr
[i
].sh_size
/ sizeof(*obj
->syms
);
122 static void outelf_init(struct outelf
*oe
)
124 memset(oe
, 0, sizeof(*oe
));
125 oe
->ehdr
.e_ident
[0] = 0x7f;
126 oe
->ehdr
.e_ident
[1] = 'E';
127 oe
->ehdr
.e_ident
[2] = 'L';
128 oe
->ehdr
.e_ident
[3] = 'F';
129 oe
->ehdr
.e_ident
[4] = ELFCLASS32
;
130 oe
->ehdr
.e_ident
[5] = ELFDATA2LSB
;
131 oe
->ehdr
.e_ident
[6] = EV_CURRENT
;
132 oe
->ehdr
.e_type
= ET_EXEC
;
133 oe
->ehdr
.e_machine
= EM_386
;
134 oe
->ehdr
.e_version
= EV_CURRENT
;
135 oe
->ehdr
.e_shstrndx
= SHN_UNDEF
;
136 oe
->ehdr
.e_ehsize
= sizeof(oe
->ehdr
);
137 oe
->ehdr
.e_phentsize
= sizeof(oe
->phdr
[0]);
138 oe
->ehdr
.e_shentsize
= sizeof(Elf32_Shdr
);
141 static struct secmap
*outelf_mapping(struct outelf
*oe
, Elf32_Shdr
*shdr
)
144 for (i
= 0; i
< oe
->nsecs
; i
++)
145 if (oe
->secs
[i
].o_shdr
== shdr
)
150 static int outelf_find(struct outelf
*oe
, char *name
,
151 struct obj
**sym_obj
, Elf32_Sym
**sym_sym
)
154 for (i
= 0; i
< oe
->nobjs
; i
++) {
155 struct obj
*obj
= &oe
->objs
[i
];
157 if ((sym
= obj_find(obj
, name
))) {
166 static unsigned long bss_addr(struct outelf
*oe
, Elf32_Sym
*sym
)
169 for (i
= 0; i
< oe
->nbss_syms
; i
++)
170 if (oe
->bss_syms
[i
].sym
== sym
)
171 return oe
->bss_vaddr
+ oe
->bss_syms
[i
].off
;
175 static void die(char *msg
)
177 fprintf(stderr
, "%s\n", msg
);
181 static void die_undef(char *name
)
183 fprintf(stderr
, "%s undefined\n", name
);
187 static unsigned long symval(struct outelf
*oe
, struct obj
*obj
, Elf32_Sym
*sym
)
190 char *name
= obj
? obj
->symstr
+ sym
->st_name
: NULL
;
192 switch (ELF32_ST_TYPE(sym
->st_info
)) {
194 if ((sec
= outelf_mapping(oe
, &obj
->shdr
[sym
->st_shndx
])))
200 if (name
&& *name
&& sym
->st_shndx
== SHN_UNDEF
)
201 if (outelf_find(oe
, name
, &obj
, &sym
))
203 if (sym
->st_shndx
== SHN_COMMON
)
204 return bss_addr(oe
, sym
);
205 s_idx
= sym
->st_shndx
;
206 s_off
= sym
->st_value
;
207 sec
= outelf_mapping(oe
, &obj
->shdr
[s_idx
]);
208 if ((sec
= outelf_mapping(oe
, &obj
->shdr
[s_idx
])))
209 return sec
->vaddr
+ s_off
;
214 static unsigned long outelf_addr(struct outelf
*oe
, char *name
)
218 if (outelf_find(oe
, name
, &obj
, &sym
))
220 return symval(oe
, obj
, sym
);
223 static void outelf_reloc_sec(struct outelf
*oe
, int o_idx
, int s_idx
)
225 struct obj
*obj
= &oe
->objs
[o_idx
];
226 Elf32_Shdr
*rel_shdr
= &obj
->shdr
[s_idx
];
227 Elf32_Rel
*rels
= (void *) obj
->mem
+ obj
->shdr
[s_idx
].sh_offset
;
228 Elf32_Shdr
*other_shdr
= &obj
->shdr
[rel_shdr
->sh_info
];
229 void *other
= (void *) obj
->mem
+ other_shdr
->sh_offset
;
230 int nrels
= rel_shdr
->sh_size
/ sizeof(*rels
);
233 for (i
= 0; i
< nrels
; i
++) {
234 Elf32_Rela
*rel
= (void *) &rels
[i
];
235 int sym_idx
= ELF32_R_SYM(rel
->r_info
);
236 Elf32_Sym
*sym
= &obj
->syms
[sym_idx
];
237 unsigned long val
= symval(oe
, obj
, sym
);
238 unsigned long *dst
= other
+ rel
->r_offset
;
239 switch (ELF32_R_TYPE(rel
->r_info
)) {
243 *(unsigned short *) dst
+= val
;
250 addr
= outelf_mapping(oe
, other_shdr
)->vaddr
+
255 die("unknown relocation type");
260 static void outelf_reloc(struct outelf
*oe
)
263 for (i
= 0; i
< oe
->nobjs
; i
++) {
264 struct obj
*obj
= &oe
->objs
[i
];
265 for (j
= 0; j
< obj
->ehdr
->e_shnum
; j
++)
266 if (obj
->shdr
[j
].sh_type
== SHT_REL
)
267 outelf_reloc_sec(oe
, i
, j
);
271 static void alloc_bss(struct outelf
*oe
, Elf32_Sym
*sym
)
273 int n
= oe
->nbss_syms
++;
274 int off
= ALIGN(oe
->bss_len
, MAX(sym
->st_value
, 4));
275 oe
->bss_syms
[n
].sym
= sym
;
276 oe
->bss_syms
[n
].off
= off
;
277 oe
->bss_len
= off
+ sym
->st_size
;
280 static void outelf_bss(struct outelf
*oe
)
283 for (i
= 0; i
< oe
->nobjs
; i
++) {
284 struct obj
*obj
= &oe
->objs
[i
];
285 for (j
= 0; j
< obj
->nsyms
; j
++)
286 if (obj
->syms
[j
].st_shndx
== SHN_COMMON
)
287 alloc_bss(oe
, &obj
->syms
[j
]);
291 #define SEC_CODE(s) ((s)->sh_flags & SHF_EXECINSTR)
292 #define SEC_BSS(s) ((s)->sh_type == SHT_NOBITS)
293 #define SEC_DATA(s) (!SEC_CODE(s) && !SEC_BSS(s))
295 static char *putstr(char *d
, char *s
)
303 static void build_symtab(struct outelf
*oe
)
306 char *symstr
= oe
->symstr
;
307 Elf32_Sym
*syms
= oe
->syms
;
308 Elf32_Shdr
*sym_shdr
= &oe
->shdr
[1];
309 Elf32_Shdr
*str_shdr
= &oe
->shdr
[2];
311 char *s
= putstr(symstr
, "");
312 int faddr
= oe
->shdr_faddr
;
314 for (i
= 0; i
< oe
->nobjs
; i
++) {
315 struct obj
*obj
= &oe
->objs
[i
];
316 for (j
= 0; j
< obj
->nsyms
; j
++) {
317 Elf32_Sym
*sym
= &obj
->syms
[j
];
318 int type
= ELF32_ST_TYPE(sym
->st_info
);
319 int bind
= ELF32_ST_BIND(sym
->st_info
);
320 char *name
= obj
->symstr
+ sym
->st_name
;
321 if (!*name
|| bind
== STB_LOCAL
||
322 sym
->st_shndx
== SHN_UNDEF
)
324 syms
[n
].st_name
= s
- symstr
;
326 syms
[n
].st_info
= ELF32_ST_INFO(bind
, type
);
327 syms
[n
].st_value
= symval(oe
, obj
, sym
);
328 syms
[n
].st_size
= sym
->st_size
;
329 syms
[n
].st_shndx
= SHN_ABS
;
333 oe
->nsymstr
= s
- symstr
;
336 oe
->shdr_faddr
= faddr
;
337 faddr
+= oe
->nsh
* sizeof(oe
->shdr
[0]);
338 oe
->syms_faddr
= faddr
;
339 faddr
+= oe
->nsyms
* sizeof(oe
->syms
[0]);
340 oe
->symstr_faddr
= faddr
;
341 faddr
+= oe
->nsymstr
;
343 oe
->ehdr
.e_shstrndx
= str_shdr
- oe
->shdr
;
344 oe
->ehdr
.e_shoff
= oe
->shdr_faddr
;
345 oe
->ehdr
.e_shnum
= oe
->nsh
;
347 str_shdr
->sh_name
= 0;
348 str_shdr
->sh_type
= SHT_STRTAB
;
349 str_shdr
->sh_offset
= oe
->symstr_faddr
;
350 str_shdr
->sh_size
= oe
->nsymstr
;
352 sym_shdr
->sh_name
= 0;
353 sym_shdr
->sh_type
= SHT_SYMTAB
;
354 sym_shdr
->sh_entsize
= sizeof(oe
->syms
[0]);
355 sym_shdr
->sh_offset
= oe
->syms_faddr
;
356 sym_shdr
->sh_size
= oe
->nsyms
* sizeof(oe
->syms
[0]);
357 sym_shdr
->sh_link
= str_shdr
- oe
->shdr
;
358 sym_shdr
->sh_info
= 0;
361 static void outelf_write(struct outelf
*oe
, int fd
)
364 oe
->ehdr
.e_entry
= outelf_addr(oe
, entry
) -
365 sec_vaddr
[I_CS
] + sec_laddr
[I_CS
];
368 oe
->ehdr
.e_phnum
= oe
->nph
;
369 oe
->ehdr
.e_phoff
= sizeof(oe
->ehdr
);
370 lseek(fd
, 0, SEEK_SET
);
371 write(fd
, &oe
->ehdr
, sizeof(oe
->ehdr
));
372 write(fd
, &oe
->phdr
, oe
->nph
* sizeof(oe
->phdr
[0]));
373 for (i
= 0; i
< oe
->nsecs
; i
++) {
374 struct secmap
*sec
= &oe
->secs
[i
];
375 char *buf
= sec
->obj
->mem
+ sec
->o_shdr
->sh_offset
;
376 int len
= sec
->o_shdr
->sh_size
;
377 if (SEC_BSS(sec
->o_shdr
))
379 lseek(fd
, sec
->faddr
, SEEK_SET
);
383 lseek(fd
, oe
->shdr_faddr
, SEEK_SET
);
384 write(fd
, &oe
->shdr
, oe
->nsh
* sizeof(oe
->shdr
[0]));
385 lseek(fd
, oe
->syms_faddr
, SEEK_SET
);
386 write(fd
, &oe
->syms
, oe
->nsyms
* sizeof(oe
->syms
[0]));
387 lseek(fd
, oe
->symstr_faddr
, SEEK_SET
);
388 write(fd
, &oe
->symstr
, oe
->nsymstr
);
392 static void outelf_add(struct outelf
*oe
, char *mem
)
394 Elf32_Ehdr
*ehdr
= (void *) mem
;
395 Elf32_Shdr
*shdr
= (void *) (mem
+ ehdr
->e_shoff
);
398 if (ehdr
->e_type
!= ET_REL
)
400 if (oe
->nobjs
>= MAXOBJS
)
401 die("ld: MAXOBJS reached!");
402 obj
= &oe
->objs
[oe
->nobjs
++];
404 for (i
= 0; i
< ehdr
->e_shnum
; i
++) {
406 if (!(shdr
[i
].sh_flags
& 0x7))
408 if (oe
->nsecs
>= MAXSECS
)
409 die("ld: MAXSECS reached");
410 sec
= &oe
->secs
[oe
->nsecs
++];
411 sec
->o_shdr
= &shdr
[i
];
416 static int link_cs(struct outelf
*oe
, Elf32_Phdr
*phdr
, unsigned long faddr
,
417 unsigned long vaddr
, unsigned long laddr
, int len
)
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
))
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 phdr
->p_type
= PT_LOAD
;
431 phdr
->p_flags
= PF_R
| PF_W
| PF_X
;
432 phdr
->p_vaddr
= vaddr
;
433 phdr
->p_paddr
= laddr
;
434 phdr
->p_offset
= faddr
;
435 phdr
->p_filesz
= len
;
437 phdr
->p_align
= PAGE_SIZE
;
441 static int link_ds(struct outelf
*oe
, Elf32_Phdr
*phdr
, unsigned long faddr
,
442 unsigned long vaddr
, unsigned long laddr
)
446 for (i
= 0; i
< oe
->nsecs
; i
++) {
447 struct secmap
*sec
= &oe
->secs
[i
];
448 if (!SEC_DATA(sec
->o_shdr
))
450 sec
->vaddr
= vaddr
+ len
;
451 sec
->faddr
= faddr
+ len
;
452 len
+= sec
->o_shdr
->sh_size
;
455 phdr
->p_type
= PT_LOAD
;
456 phdr
->p_flags
= PF_R
| PF_W
| PF_X
;
457 phdr
->p_align
= PAGE_SIZE
;
458 phdr
->p_vaddr
= vaddr
;
459 phdr
->p_paddr
= laddr
;
460 phdr
->p_filesz
= len
;
462 phdr
->p_offset
= faddr
;
466 static int link_bss(struct outelf
*oe
, Elf32_Phdr
*phdr
,
467 unsigned long faddr
, unsigned long vaddr
, int len
)
470 for (i
= 0; i
< oe
->nsecs
; i
++) {
471 struct secmap
*sec
= &oe
->secs
[i
];
472 int alignment
= MAX(sec
->o_shdr
->sh_addralign
, 4);
473 if (!SEC_BSS(sec
->o_shdr
))
475 len
= ALIGN(vaddr
+ len
, alignment
) - vaddr
;
476 sec
->vaddr
= vaddr
+ len
;
478 len
+= sec
->o_shdr
->sh_size
;
480 phdr
->p_type
= PT_LOAD
;
481 phdr
->p_flags
= PF_R
| PF_W
;
482 phdr
->p_vaddr
= vaddr
;
483 phdr
->p_paddr
= vaddr
;
484 phdr
->p_offset
= faddr
;
487 phdr
->p_align
= PAGE_SIZE
;
491 static void outelf_link(struct outelf
*oe
)
493 unsigned long faddr
, vaddr
, laddr
;
495 len
= ALIGN(sizeof(oe
->ehdr
) + MAXPHDRS
* sizeof(oe
->phdr
[0]), secalign
);
496 faddr
= len
& ~PAGE_MASK
;
497 vaddr
= sec_vaddr
[I_CS
];
498 laddr
= sec_laddr
[I_CS
];
499 len
= link_cs(oe
, &oe
->phdr
[0], faddr
, vaddr
, laddr
, len
& PAGE_MASK
);
501 len
= ALIGN(faddr
+ len
, secalign
) - faddr
;
503 vaddr
= sec_set
[I_DS
] ? sec_vaddr
[I_DS
] | (faddr
& PAGE_MASK
) : vaddr
+ len
;
504 laddr
= sec_set
[I_DS
] ? sec_laddr
[I_DS
] | (faddr
& PAGE_MASK
) : laddr
+ len
;
505 len
= link_ds(oe
, &oe
->phdr
[1], faddr
, vaddr
, laddr
);
507 len
= ALIGN(faddr
+ len
, secalign
) - faddr
;
509 vaddr
= sec_set
[I_BSS
] ? sec_vaddr
[I_BSS
] | (faddr
& PAGE_MASK
) : vaddr
+ len
;
511 oe
->bss_vaddr
= vaddr
;
512 len
= link_bss(oe
, &oe
->phdr
[2], faddr
, vaddr
, oe
->bss_len
);
516 oe
->shdr_faddr
= faddr
;
529 static int get_be32(unsigned char *s
)
531 return s
[3] | (s
[2] << 8) | (s
[1] << 16) | (s
[0] << 24);
534 static int sym_undef(struct outelf
*oe
, char *name
)
538 for (i
= 0; i
< oe
->nobjs
; i
++) {
539 struct obj
*obj
= &oe
->objs
[i
];
540 for (j
= 0; j
< obj
->nsyms
; j
++) {
541 Elf32_Sym
*sym
= &obj
->syms
[j
];
542 if (ELF32_ST_BIND(sym
->st_info
) == STB_LOCAL
)
544 if (strcmp(name
, obj
->symstr
+ sym
->st_name
))
546 if (sym
->st_shndx
!= SHN_UNDEF
)
554 static int outelf_ar_link(struct outelf
*oe
, char *ar
, int base
)
558 int nsyms
= get_be32((void *) ar
);
562 ar_name
= ar_index
+ nsyms
* 4;
563 for (i
= 0; i
< nsyms
; i
++) {
564 int off
= get_be32((void *) ar_index
+ i
* 4) +
565 sizeof(struct arhdr
);
566 if (sym_undef(oe
, ar_name
)) {
567 outelf_add(oe
, ar
- base
+ off
);
570 ar_name
= strchr(ar_name
, '\0') + 1;
575 static void outelf_archive(struct outelf
*oe
, char *ar
)
582 struct arhdr
*hdr
= (void *) ar
;
583 char *name
= hdr
->ar_name
;
586 hdr
->ar_size
[sizeof(hdr
->ar_size
) - 1] = '\0';
587 size
= atoi(hdr
->ar_size
);
588 size
= (size
+ 1) & ~1;
589 if (name
[0] == '/' && name
[1] == ' ') {
590 while (outelf_ar_link(oe
, ar
, ar
- beg
))
594 if (name
[0] == '/' && name
[1] == '/' && name
[2] == ' ')
600 static long filesize(int fd
)
607 static char *fileread(char *path
)
609 int fd
= open(path
, O_RDONLY
);
610 int size
= filesize(fd
);
611 char *buf
= malloc(size
);
617 static int is_ar(char *path
)
619 int len
= strlen(path
);
620 return len
> 2 && path
[len
- 2] == '.' && path
[len
- 1] == 'a';
623 #define LIBDIRS (1 << 5)
624 #define PATHLEN (1 << 8)
626 static char *libdirs
[LIBDIRS
] = {"/lib"};
627 static int nlibdirs
= 1;
629 static int lib_find(char *path
, char *lib
)
633 for (i
= 0; i
< nlibdirs
; i
++) {
634 sprintf(path
, "%s/lib%s.a", libdirs
[i
], lib
);
635 if (!stat(path
, &st
))
641 unsigned long hexnum(char *s
)
644 if (s
[0] == '0' && s
[1] == 'x')
646 for (; isdigit(*s
) || isalpha(*s
); s
++) {
648 n
|= isdigit(*s
) ? *s
- '0' : tolower(*s
) - 'a' + 10;
653 static void set_addr(int sec
, char *arg
)
656 char *sep
= strchr(arg
, ':');
661 sec_vaddr
[idx
] = hexnum(arg
);
662 sec_laddr
[idx
] = sep
? hexnum(sep
+ 1) : sec_vaddr
[idx
];
666 static char *obj_add(struct outelf
*oe
, char *path
)
668 char *buf
= fileread(path
);
670 die("cannot open object");
672 outelf_archive(oe
, buf
);
678 int main(int argc
, char **argv
)
680 char out
[PATHLEN
] = "a.out";
687 die("no object given");
691 if (argv
[i
][0] != '-') {
692 mem
[nmem
++] = obj_add(&oe
, argv
[i
]);
695 if (argv
[i
][1] == 'l') {
697 if (lib_find(path
, argv
[i
] + 2))
698 die("cannot find library");
699 mem
[nmem
++] = obj_add(&oe
, path
);
702 if (argv
[i
][1] == 'L') {
703 libdirs
[nlibdirs
++] = argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
];
706 if (argv
[i
][1] == 'o') {
707 strcpy(out
, argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
]);
710 if (argv
[i
][1] == 's') {
714 if (argv
[i
][1] == 'g')
716 if (argv
[i
][1] == 'm') {
717 char sec
= argv
[i
][2];
718 char *arg
= argv
[i
][3] == '=' ? argv
[i
] + 4 : argv
[++i
];
722 if (argv
[i
][1] == 'p') {
723 secalign
= PAGE_SIZE
;
726 if (argv
[i
][1] == 'e') {
727 entry
= argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
];
732 fd
= open(out
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0700);
733 outelf_write(&oe
, fd
);
735 for (i
= 0; i
< nmem
; i
++)