8 #define MAXSECS (1 << 10)
9 #define MAXOBJS (1 << 7)
10 #define PAGESIZE (1 << 12)
12 #define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
13 #define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
33 Elf64_Phdr phdr
[MAXSECS
];
35 struct secmap secs
[MAXSECS
];
37 struct obj objs
[MAXOBJS
];
43 static int obj_find(struct obj
*obj
, char *name
, int *s_idx
, int *s_off
)
46 for (i
= 0; i
< obj
->nsyms
; i
++) {
47 Elf64_Sym
*sym
= &obj
->syms
[i
];
48 if (ELF64_ST_BIND(sym
->st_info
) == STB_LOCAL
||
49 sym
->st_shndx
== SHN_UNDEF
)
51 if (!strcmp(name
, obj
->symstr
+ sym
->st_name
)) {
52 *s_idx
= sym
->st_shndx
;
53 *s_off
= sym
->st_value
;
60 static void obj_init(struct obj
*obj
, char *mem
)
64 obj
->ehdr
= (void *) mem
;
65 obj
->shdr
= (void *) (mem
+ obj
->ehdr
->e_shoff
);
66 obj
->shstr
= mem
+ obj
->shdr
[obj
->ehdr
->e_shstrndx
].sh_offset
;
67 for (i
= 0; i
< obj
->ehdr
->e_shnum
; i
++) {
68 if (obj
->shdr
[i
].sh_type
!= SHT_SYMTAB
)
70 obj
->symstr
= mem
+ obj
->shdr
[obj
->shdr
[i
].sh_link
].sh_offset
;
71 obj
->syms
= (void *) (mem
+ obj
->shdr
[i
].sh_offset
);
72 obj
->nsyms
= obj
->shdr
[i
].sh_size
/ sizeof(*obj
->syms
);
76 static void outelf_init(struct outelf
*oe
)
78 memset(oe
, 0, sizeof(*oe
));
79 oe
->ehdr
.e_ident
[0] = 0x7f;
80 oe
->ehdr
.e_ident
[1] = 'E';
81 oe
->ehdr
.e_ident
[2] = 'L';
82 oe
->ehdr
.e_ident
[3] = 'F';
83 oe
->ehdr
.e_ident
[4] = ELFCLASS64
;
84 oe
->ehdr
.e_ident
[5] = ELFDATA2LSB
;
85 oe
->ehdr
.e_ident
[6] = EV_CURRENT
;
86 oe
->ehdr
.e_ident
[7] = ELFOSABI_LINUX
;
87 oe
->ehdr
.e_type
= ET_EXEC
;
88 oe
->ehdr
.e_machine
= EM_X86_64
;
89 oe
->ehdr
.e_version
= EV_CURRENT
;
90 oe
->ehdr
.e_shstrndx
= SHN_UNDEF
;
91 oe
->ehdr
.e_ehsize
= sizeof(oe
->ehdr
);
92 oe
->faddr
= sizeof(oe
->ehdr
);
93 oe
->ehdr
.e_phentsize
= sizeof(oe
->phdr
[0]);
94 oe
->ehdr
.e_shentsize
= sizeof(Elf64_Shdr
);
95 oe
->vaddr
= 0x800000l
+ oe
->faddr
;
98 static struct secmap
*outelf_mapping(struct outelf
*oe
, Elf64_Shdr
*shdr
)
101 for (i
= 0; i
< oe
->nsecs
; i
++)
102 if (oe
->secs
[i
].o_shdr
== shdr
)
107 static unsigned long outelf_find(struct outelf
*oe
, char *name
)
111 for (i
= 0; i
< oe
->nobjs
; i
++) {
112 struct obj
*obj
= &oe
->objs
[i
];
113 if (!obj_find(obj
, name
, &s_idx
, &s_off
)) {
115 if ((sec
= outelf_mapping(oe
, &obj
->shdr
[s_idx
])))
116 return sec
->phdr
->p_vaddr
+ s_off
;
122 static unsigned long symval(struct outelf
*oe
, struct obj
*obj
, Elf64_Sym
*sym
)
125 char *name
= obj
->symstr
+ sym
->st_name
;
126 switch (ELF64_ST_TYPE(sym
->st_info
)) {
128 if ((sec
= outelf_mapping(oe
, &obj
->shdr
[sym
->st_shndx
])))
129 return sec
->phdr
->p_vaddr
;
135 return outelf_find(oe
, name
);
141 static void outelf_reloc_sec(struct outelf
*oe
, int o_idx
, int s_idx
)
143 struct obj
*obj
= &oe
->objs
[o_idx
];
144 Elf64_Shdr
*rel_shdr
= &obj
->shdr
[s_idx
];
145 Elf64_Rela
*rel
= (void *) obj
->mem
+ obj
->shdr
[s_idx
].sh_offset
;
146 Elf64_Shdr
*other_shdr
= &obj
->shdr
[rel_shdr
->sh_info
];
147 void *other
= (void *) obj
->mem
+ other_shdr
->sh_offset
;
148 int nrel
= rel_shdr
->sh_size
/ sizeof(*rel
);
151 for (i
= 0; i
< nrel
; i
++) {
152 int sym_idx
= ELF64_R_SYM(rel
[i
].r_info
);
153 Elf64_Sym
*sym
= &obj
->syms
[sym_idx
];
154 unsigned long val
= symval(oe
, obj
, sym
);
155 char *name
= obj
->symstr
+ sym
->st_name
;
156 unsigned long *dst
= other
+ rel
[i
].r_offset
;
157 switch (ELF64_R_TYPE(rel
[i
].r_info
)) {
159 *(unsigned int *) dst
= val
+ rel
[i
].r_addend
;
162 *dst
= val
+ rel
[i
].r_addend
;
165 addr
= outelf_mapping(oe
, other_shdr
)->phdr
->p_vaddr
+
167 *(unsigned int *) dst
= val
- addr
+ rel
[i
].r_addend
- 4;
173 static void outelf_reloc(struct outelf
*oe
)
176 for (i
= 0; i
< oe
->nobjs
; i
++) {
177 struct obj
*obj
= &oe
->objs
[i
];
178 for (j
= 0; j
< obj
->ehdr
->e_shnum
; j
++)
179 if (obj
->shdr
[j
].sh_type
== SHT_RELA
)
180 outelf_reloc_sec(oe
, i
, j
);
184 static void outelf_write(struct outelf
*oe
, int fd
)
187 oe
->ehdr
.e_entry
= outelf_find(oe
, "_start");
189 oe
->ehdr
.e_phnum
= oe
->nph
;
190 oe
->ehdr
.e_phoff
= oe
->faddr
;
191 oe
->ehdr
.e_shnum
= 0;
192 oe
->ehdr
.e_shoff
= 0;
193 write(fd
, &oe
->ehdr
, sizeof(oe
->ehdr
));
194 for (i
= 0; i
< oe
->nsecs
; i
++) {
195 struct secmap
*sec
= &oe
->secs
[i
];
196 char *buf
= sec
->obj
->mem
+ sec
->o_shdr
->sh_offset
;
197 int len
= sec
->o_shdr
->sh_size
;
198 lseek(fd
, sec
->phdr
->p_offset
, SEEK_SET
);
201 lseek(fd
, oe
->faddr
, SEEK_SET
);
202 write(fd
, &oe
->phdr
, oe
->nph
* sizeof(oe
->phdr
[0]));
205 static void outelf_link(struct outelf
*oe
, char *mem
)
207 Elf64_Ehdr
*ehdr
= (void *) mem
;
208 Elf64_Shdr
*shdr
= (void *) (mem
+ ehdr
->e_shoff
);
209 struct obj
*obj
= &oe
->objs
[oe
->nobjs
++];
211 if (ehdr
->e_type
!= ET_REL
)
214 for (i
= 0; i
< ehdr
->e_shnum
; i
++) {
216 if (!(shdr
[i
].sh_flags
& 0x7))
218 sec
= &oe
->secs
[oe
->nsecs
++];
219 sec
->o_shdr
= &shdr
[i
];
220 sec
->phdr
= &oe
->phdr
[oe
->nph
++];
222 sec
->phdr
->p_type
= PT_LOAD
;
223 sec
->phdr
->p_flags
= PF_R
| PF_W
| PF_X
;
224 sec
->phdr
->p_vaddr
= oe
->vaddr
;
225 sec
->phdr
->p_paddr
= oe
->vaddr
;
226 sec
->phdr
->p_offset
= oe
->faddr
;
227 sec
->phdr
->p_filesz
= shdr
[i
].sh_size
;
228 sec
->phdr
->p_memsz
= shdr
[i
].sh_size
;
229 sec
->phdr
->p_align
= PAGESIZE
;
230 oe
->faddr
+= shdr
[i
].sh_size
;
231 oe
->vaddr
+= shdr
[i
].sh_size
;
235 static void outelf_free(struct outelf
*oe
)
238 for (i
= 0; i
< oe
->nobjs
; i
++)
239 free(oe
->objs
[i
].mem
);
242 static long filesize(int fd
)
249 static char *fileread(char *path
)
251 int fd
= open(path
, O_RDONLY
);
252 int size
= filesize(fd
);
253 char *buf
= malloc(size
);
259 static void die(char *msg
)
261 write(1, msg
, strlen(msg
));
265 int main(int argc
, char **argv
)
267 char out
[1 << 10] = "a.out";
273 die("no object given\n");
277 if (!strcmp("-o", argv
[i
])) {
278 strcpy(out
, argv
[++i
]);
281 buf
= fileread(argv
[i
]);
283 die("cannot open object\n");
284 outelf_link(&oe
, buf
);
286 fd
= open(out
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0700);
288 outelf_write(&oe
, fd
);