5 #define MAXSECS (1 << 7)
6 #define MAXSYMS (1 << 10)
8 #define SECSIZE (1 << 12)
9 #define MAXRELA (1 << 10)
15 static Elf64_Ehdr ehdr
;
16 static Elf64_Shdr shdr
[MAXSECS
];
17 static int nshdr
= SEC_BEG
;
18 static Elf64_Sym syms
[MAXSYMS
];
20 static char symstr
[MAXSYMS
* 8];
21 static int nsymstr
= 1;
26 Elf64_Rela rela
[MAXRELA
];
32 static struct sec
*sec
;
34 #define MAXTEMP (1 << 12)
46 static void putint(char *s
, long n
, int l
)
54 static char *putstr(char *s
, char *r
)
62 static Elf64_Sym
*put_sym(char *name
)
64 Elf64_Sym
*sym
= &syms
[nsyms
++];
65 sym
->st_name
= nsymstr
;
66 nsymstr
= putstr(symstr
+ nsymstr
, name
) - symstr
;
67 sym
->st_info
= ELF64_ST_INFO(STB_GLOBAL
, STT_FUNC
);
71 static void os(char *s
, int n
)
77 static void oi(long n
, int l
)
85 static int tmp_pop(void)
87 os("\x48\x8b\x85", 3); /* mov top(%rbp), %rax */
88 oi(-tmp
[--ntmp
].addr
, 4);
89 return tmp
[ntmp
].type
;
92 static void tmp_push(int type
)
95 tmp
[ntmp
].type
= type
;
97 os("\x48\x89\x85", 3); /* mov %rax, top(%rbp) */
98 oi(-tmp
[ntmp
++].addr
, 4);
102 void o_func_beg(char *name
)
104 Elf64_Sym
*sym
= put_sym(name
);
105 sec
= &secs
[nsecs
++];
106 sym
->st_shndx
= nshdr
;
107 sec
->sec_shdr
= &shdr
[nshdr
++];
108 sec
->rel_shdr
= &shdr
[nshdr
++];
109 sec
->rel_shdr
->sh_link
= SEC_SYMS
;
110 sec
->rel_shdr
->sh_info
= sec
->sec_shdr
- shdr
;
113 os("\x48\x89\xe5", 3);
116 os("\x48\x83\xec", 3);
127 static void deref(void)
129 os("\x48\x8b\x00", 3); /* mov (%rax), %rax */
134 if (tmp_pop() == TMP_ADDR
)
142 if (tmp_pop() == TMP_ADDR
)
145 os("\x48\x31\xc0", 3); /* xor %rax, %rax */
147 os("\xc9\xc3", 2); /* leave; ret; */
150 void o_func_end(void)
152 os("\xc9\xc3", 2); /* leave; ret; */
153 sec
->len
= cur
- sec
->buf
;
156 void o_local(long addr
)
158 os("\x48\x89\xe8", 3); /* mov %rbp, %rax */
159 os("\x48\x05", 2); /* add $addr, %rax */
171 void o_rmlocal(long addr
)
179 long addr
= o_mklocal();
180 mov
[0] = "\x48\x48\x48\x48\x4c\x4c"[i
];
182 mov
[2] = "\xbd\xb5\x95\x8d\x85\x8d"[i
];
183 os(mov
, 3); /* mov %xxx, addr(%rbp) */
190 if (tmp_pop() == TMP_ADDR
)
192 os("\x48\x89\xc3", 3); /* mov %rax, %rbx */
194 os("\x48\x89\x18", 3); /* mov %rbx, (%rax) */
197 static long codeaddr(void)
199 return cur
- sec
->buf
;
209 os("\x48\x85\xc0", 3); /* test %rax, %rax */
210 os("\x0f\x84", 2); /* jz $addr */
211 oi(codeaddr() - addr
- 4, 4);
217 return cur
- sec
->buf
- 4;
220 void o_filljz(long addr
)
222 putint(sec
->buf
+ addr
, codeaddr() - addr
- 4, 4);
229 static int sym_find(char *name
)
232 for (i
= 0; i
< nsyms
; i
++)
233 if (!strcmp(name
, symstr
+ syms
[i
].st_name
))
238 void o_symaddr(char *name
)
240 Elf64_Rela
*rela
= &sec
->rela
[sec
->nrela
++];
241 os("\x48\xc7\xc0", 3); /* mov $addr, %rax */
242 rela
->r_offset
= codeaddr();
243 rela
->r_info
= ELF64_R_INFO(sym_find(name
), R_X86_64_32
);
248 static void setarg(int i
)
251 mov
[0] = "\x48\x48\x48\x48\x49\x49"[i
];
253 mov
[2] = "\xc7\xc6\xc2\xc1\xc0\xc1"[i
];
254 os(mov
, 3); /* mov %rax, %xxx */
257 void o_call(int argc
)
261 os("\x48\x31\xc0", 3); /* xor %rax, %rax */
262 for (i
= 0; i
< argc
; i
++) {
263 if (tmp_pop() == TMP_ADDR
)
265 setarg(argc
- i
- 1);
268 os("\xff\xd0", 2); /* callq *%rax */
272 void out_write(int fd
)
274 Elf64_Shdr
*symstr_shdr
= &shdr
[SEC_SYMSTR
];
275 Elf64_Shdr
*syms_shdr
= &shdr
[SEC_SYMS
];
276 unsigned long offset
= sizeof(ehdr
);
279 ehdr
.e_ident
[0] = 0x7f;
280 ehdr
.e_ident
[1] = 'E';
281 ehdr
.e_ident
[2] = 'L';
282 ehdr
.e_ident
[3] = 'F';
283 ehdr
.e_ident
[4] = ELFCLASS64
;
284 ehdr
.e_ident
[5] = ELFDATA2LSB
;
285 ehdr
.e_ident
[6] = EV_CURRENT
;
286 ehdr
.e_type
= ET_REL
;
287 ehdr
.e_machine
= EM_X86_64
;
288 ehdr
.e_version
= EV_CURRENT
;
289 ehdr
.e_ehsize
= sizeof(ehdr
);
290 ehdr
.e_shentsize
= sizeof(shdr
[0]);
291 ehdr
.e_shoff
= offset
;
292 ehdr
.e_shnum
= nshdr
;
293 ehdr
.e_shstrndx
= SEC_SYMSTR
;
294 offset
+= sizeof(shdr
[0]) * nshdr
;
296 syms_shdr
->sh_type
= SHT_SYMTAB
;
297 syms_shdr
->sh_offset
= offset
;
298 syms_shdr
->sh_size
= nsyms
* sizeof(syms
[0]);
299 syms_shdr
->sh_entsize
= sizeof(syms
[0]);
300 syms_shdr
->sh_link
= SEC_SYMSTR
;
301 offset
+= syms_shdr
->sh_size
;
303 symstr_shdr
->sh_type
= SHT_STRTAB
;
304 symstr_shdr
->sh_offset
= offset
;
305 symstr_shdr
->sh_size
= nsymstr
;
306 symstr_shdr
->sh_entsize
= 1;
307 offset
+= symstr_shdr
->sh_size
;
309 for (i
= 0; i
< nsecs
; i
++) {
310 struct sec
*sec
= &secs
[i
];
312 sec
->sec_shdr
->sh_type
= SHT_PROGBITS
;
313 sec
->sec_shdr
->sh_flags
= SHF_EXECINSTR
;
314 sec
->sec_shdr
->sh_offset
= offset
;
315 sec
->sec_shdr
->sh_size
= sec
->len
;
316 sec
->sec_shdr
->sh_entsize
= 1;
317 offset
+= sec
->sec_shdr
->sh_size
;
319 sec
->rel_shdr
->sh_type
= SHT_RELA
;
320 sec
->rel_shdr
->sh_offset
= offset
;
321 sec
->rel_shdr
->sh_size
= sec
->nrela
* sizeof(sec
->rela
[0]);
322 sec
->rel_shdr
->sh_entsize
= sizeof(sec
->rela
[0]);
323 offset
+= sec
->rel_shdr
->sh_size
;
326 write(fd
, &ehdr
, sizeof(ehdr
));
327 write(fd
, shdr
, sizeof(shdr
[0]) * nshdr
);
328 write(fd
, syms
, sizeof(syms
[0]) * nsyms
);
329 write(fd
, symstr
, nsymstr
);
330 for (i
= 0; i
< nsecs
; i
++) {
331 struct sec
*sec
= &secs
[i
];
332 write(fd
, sec
->buf
, sec
->len
);
333 write(fd
, sec
->rela
, sec
->nrela
* sizeof(sec
->rela
[0]));