2 * ld - a small static linker
4 * Copyright (C) 2010-2011 Ali Gholami Rudi
6 * This program is released under GNU GPL version 2.
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)
27 #define MAX(a, b) ((a) > (b) ? (a) : (b))
28 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
54 Elf32_Phdr phdr
[MAXSECS
];
56 struct secmap secs
[MAXSECS
];
58 struct obj objs
[MAXOBJS
];
62 unsigned long code_addr
;
65 struct bss_sym bss_syms
[MAXSYMS
];
67 unsigned long bss_vaddr
;
71 Elf32_Shdr shdr
[MAXSECS
];
74 Elf32_Sym syms
[MAXSYMS
];
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
)
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
)
92 if (!strcmp(name
, obj
->symstr
+ sym
->st_name
))
98 static void obj_init(struct obj
*obj
, char *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
)
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
)
136 for (i
= 0; i
< oe
->nsecs
; i
++)
137 if (oe
->secs
[i
].o_shdr
== shdr
)
142 static int outelf_find(struct outelf
*oe
, char *name
,
143 struct obj
**sym_obj
, Elf32_Sym
**sym_sym
)
146 for (i
= 0; i
< oe
->nobjs
; i
++) {
147 struct obj
*obj
= &oe
->objs
[i
];
149 if ((sym
= obj_find(obj
, name
))) {
158 static unsigned long bss_addr(struct outelf
*oe
, Elf32_Sym
*sym
)
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
;
167 static void die(char *msg
)
169 write(1, msg
, strlen(msg
));
173 static void warn_undef(char *name
)
177 strcpy(msg
+ strlen(msg
), " undefined\n");
181 static unsigned long symval(struct outelf
*oe
, struct obj
*obj
, Elf32_Sym
*sym
)
184 char *name
= obj
? obj
->symstr
+ sym
->st_name
: NULL
;
186 switch (ELF32_ST_TYPE(sym
->st_info
)) {
188 if ((sec
= outelf_mapping(oe
, &obj
->shdr
[sym
->st_shndx
])))
194 if (name
&& *name
&& sym
->st_shndx
== SHN_UNDEF
)
195 if (outelf_find(oe
, name
, &obj
, &sym
))
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
;
208 static unsigned long outelf_addr(struct outelf
*oe
, char *name
)
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
);
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
)) {
237 *(unsigned short *) dst
+= val
;
244 addr
= outelf_mapping(oe
, other_shdr
)->vaddr
+
249 die("unknown relocation type\n");
254 static void outelf_reloc(struct outelf
*oe
)
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
)
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
)
297 static void build_symtab(struct outelf
*oe
)
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];
305 char *s
= putstr(symstr
, "");
306 int faddr
= oe
->shdr_faddr
;
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
)
318 syms
[n
].st_name
= s
- symstr
;
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
;
327 oe
->nsymstr
= s
- symstr
;
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
)
358 oe
->ehdr
.e_entry
= outelf_addr(oe
, "_start");
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
))
372 lseek(fd
, sec
->faddr
, SEEK_SET
);
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
);
391 if (ehdr
->e_type
!= ET_REL
)
393 if (oe
->nobjs
>= MAXOBJS
)
394 die("ld: MAXOBJS reached!\n");
395 obj
= &oe
->objs
[oe
->nobjs
++];
397 for (i
= 0; i
< ehdr
->e_shnum
; i
++) {
399 if (!(shdr
[i
].sh_flags
& 0x7))
401 if (oe
->nsecs
>= MAXSECS
)
402 die("ld: MAXSECS reached\n");
403 sec
= &oe
->secs
[oe
->nsecs
++];
404 sec
->o_shdr
= &shdr
[i
];
409 static void outelf_link(struct outelf
*oe
)
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]);
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
))
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
;
441 vaddr
= DATADDR
? DATADDR
+ faddr
% PAGE_SIZE
: vaddr
+ len
;
443 for (i
= 0; i
< oe
->nsecs
; i
++) {
444 struct secmap
*sec
= &oe
->secs
[i
];
445 if (!SEC_DATA(sec
->o_shdr
))
447 sec
->vaddr
= vaddr
+ len
;
448 sec
->faddr
= faddr
+ len
;
449 len
+= sec
->o_shdr
->sh_size
;
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
;
463 vaddr
= BSSADDR
? BSSADDR
+ faddr
% PAGE_SIZE
: vaddr
+ len
;
466 oe
->bss_vaddr
= vaddr
+ 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
))
473 len
= ALIGN(vaddr
+ len
, alignment
) - vaddr
;
474 sec
->vaddr
= vaddr
+ len
;
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
;
488 oe
->shdr_faddr
= faddr
;
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
)
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
)
516 if (strcmp(name
, obj
->symstr
+ sym
->st_name
))
518 if (sym
->st_shndx
!= SHN_UNDEF
)
526 static int outelf_ar_link(struct outelf
*oe
, char *ar
, int base
)
530 int nsyms
= get_be32((void *) ar
);
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
);
542 ar_name
= strchr(ar_name
, '\0') + 1;
547 static void link_archive(struct outelf
*oe
, char *ar
)
554 struct arhdr
*hdr
= (void *) ar
;
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
))
565 if (!strncmp(hdr
->ar_name
, "// ", 3))
571 static long filesize(int fd
)
578 static char *fileread(char *path
)
580 int fd
= open(path
, O_RDONLY
);
581 int size
= filesize(fd
);
582 char *buf
= malloc(size
);
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";
604 die("no object given\n");
608 if (!strcmp("-o", argv
[i
])) {
609 strcpy(out
, argv
[++i
]);
612 if (!strcmp("-s", argv
[i
])) {
616 if (!strcmp("-g", argv
[i
]))
618 buf
= fileread(argv
[i
]);
621 die("cannot open object\n");
623 link_archive(&oe
, buf
);
625 outelf_add(&oe
, buf
);
628 fd
= open(out
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0700);
629 outelf_write(&oe
, fd
);
631 for (i
= 0; i
< nmem
; i
++)