add do-while support
[neatcc/cc.git] / out.c
blob0db8cd1e811f1cc2c5d3b58c4acdee6e6ae3a319
1 #include <elf.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include "gen.h"
6 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
8 #define MAXSECS (1 << 7)
9 #define MAXSYMS (1 << 10)
10 #define MAXRELA (1 << 10)
11 #define SEC_SYMS 1
12 #define SEC_SYMSTR 2
13 #define SEC_DAT 3
14 #define SEC_BSS 4
15 #define SEC_BEG 5
17 static Elf64_Ehdr ehdr;
18 static Elf64_Shdr shdr[MAXSECS];
19 static int nshdr = SEC_BEG;
20 static Elf64_Sym syms[MAXSYMS];
21 static int nsyms;
22 static char symstr[MAXSYMS * 8];
23 static int nsymstr = 1;
24 static int bsslen;
25 static char dat[SECSIZE];
26 static int datlen;
28 static struct sec {
29 char buf[SECSIZE];
30 int len;
31 Elf64_Sym *sym;
32 Elf64_Rela rela[MAXRELA];
33 int nrela;
34 Elf64_Shdr *sec_shdr;
35 Elf64_Shdr *rel_shdr;
36 } secs[MAXSECS];
37 static int nsecs;
38 static struct sec *sec;
40 static char *putstr(char *s, char *r)
42 while (*r)
43 *s++ = *r++;
44 *s++ = '\0';
45 return s;
48 static int sym_find(char *name)
50 Elf64_Sym *sym;
51 int i;
52 for (i = 0; i < nsyms; i++)
53 if (!strcmp(name, symstr + syms[i].st_name))
54 return i;
55 return -1;
58 static Elf64_Sym *put_sym(char *name)
60 int found = name ? sym_find(name) : -1;
61 Elf64_Sym *sym = name && found != -1 ? &syms[found] : &syms[nsyms++];
62 sym->st_name = 0;
63 if (found == -1 && name) {
64 sym->st_name = nsymstr;
65 nsymstr = putstr(symstr + nsymstr, name) - symstr;
67 sym->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_FUNC);
68 return sym;
71 long out_func_beg(char *name)
73 sec = &secs[nsecs++];
74 sec->sym = put_sym(name);
75 sec->sym->st_shndx = nshdr;
76 sec->sec_shdr = &shdr[nshdr++];
77 sec->rel_shdr = &shdr[nshdr++];
78 sec->rel_shdr->sh_link = SEC_SYMS;
79 sec->rel_shdr->sh_info = sec->sec_shdr - shdr;
80 return sec->sym - syms;
83 void out_func_end(char *buf, int len)
85 memcpy(sec->buf, buf, len);
86 sec->len = len;
87 sec->sym->st_size = len;
90 void out_rela(long addr, int off, int rel)
92 Elf64_Rela *rela = &sec->rela[sec->nrela++];
93 rela->r_offset = off;
94 rela->r_info = ELF64_R_INFO(addr, rel ? R_X86_64_PC32 : R_X86_64_32);
97 void out_write(int fd)
99 Elf64_Shdr *symstr_shdr = &shdr[SEC_SYMSTR];
100 Elf64_Shdr *syms_shdr = &shdr[SEC_SYMS];
101 Elf64_Shdr *dat_shdr = &shdr[SEC_DAT];
102 Elf64_Shdr *bss_shdr = &shdr[SEC_BSS];
103 unsigned long offset = sizeof(ehdr);
104 int i;
106 ehdr.e_ident[0] = 0x7f;
107 ehdr.e_ident[1] = 'E';
108 ehdr.e_ident[2] = 'L';
109 ehdr.e_ident[3] = 'F';
110 ehdr.e_ident[4] = ELFCLASS64;
111 ehdr.e_ident[5] = ELFDATA2LSB;
112 ehdr.e_ident[6] = EV_CURRENT;
113 ehdr.e_type = ET_REL;
114 ehdr.e_machine = EM_X86_64;
115 ehdr.e_version = EV_CURRENT;
116 ehdr.e_ehsize = sizeof(ehdr);
117 ehdr.e_shentsize = sizeof(shdr[0]);
118 ehdr.e_shoff = offset;
119 ehdr.e_shnum = nshdr;
120 ehdr.e_shstrndx = SEC_SYMSTR;
121 offset += sizeof(shdr[0]) * nshdr;
123 syms_shdr->sh_type = SHT_SYMTAB;
124 syms_shdr->sh_offset = offset;
125 syms_shdr->sh_size = nsyms * sizeof(syms[0]);
126 syms_shdr->sh_entsize = sizeof(syms[0]);
127 syms_shdr->sh_link = SEC_SYMSTR;
128 offset += syms_shdr->sh_size;
130 dat_shdr->sh_type = SHT_PROGBITS;
131 dat_shdr->sh_flags = SHF_WRITE;
132 dat_shdr->sh_offset = offset;
133 dat_shdr->sh_size = datlen;
134 dat_shdr->sh_entsize = 1;
135 dat_shdr->sh_addralign = 8;
136 offset += dat_shdr->sh_size;
138 bss_shdr->sh_type = SHT_NOBITS;
139 bss_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
140 bss_shdr->sh_offset = offset;
141 bss_shdr->sh_size = bsslen;
142 bss_shdr->sh_entsize = 1;
143 bss_shdr->sh_addralign = 8;
145 symstr_shdr->sh_type = SHT_STRTAB;
146 symstr_shdr->sh_offset = offset;
147 symstr_shdr->sh_size = nsymstr;
148 symstr_shdr->sh_entsize = 1;
149 offset += symstr_shdr->sh_size;
151 for (i = 0; i < nsecs; i++) {
152 struct sec *sec = &secs[i];
154 sec->sec_shdr->sh_type = SHT_PROGBITS;
155 sec->sec_shdr->sh_flags = SHF_EXECINSTR;
156 sec->sec_shdr->sh_offset = offset;
157 sec->sec_shdr->sh_size = sec->len;
158 sec->sec_shdr->sh_entsize = 1;
159 offset += sec->sec_shdr->sh_size;
161 sec->rel_shdr->sh_type = SHT_RELA;
162 sec->rel_shdr->sh_offset = offset;
163 sec->rel_shdr->sh_size = sec->nrela * sizeof(sec->rela[0]);
164 sec->rel_shdr->sh_entsize = sizeof(sec->rela[0]);
165 offset += sec->rel_shdr->sh_size;
168 write(fd, &ehdr, sizeof(ehdr));
169 write(fd, shdr, sizeof(shdr[0]) * nshdr);
170 write(fd, syms, sizeof(syms[0]) * nsyms);
171 write(fd, dat, datlen);
172 write(fd, symstr, nsymstr);
173 for (i = 0; i < nsecs; i++) {
174 struct sec *sec = &secs[i];
175 write(fd, sec->buf, sec->len);
176 write(fd, sec->rela, sec->nrela * sizeof(sec->rela[0]));
180 long o_mkvar(char *name, int size)
182 Elf64_Sym *sym = put_sym(name);
183 sym->st_shndx = SEC_BSS;
184 sym->st_value = bsslen;
185 sym->st_size = size;
186 sym->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT);
187 bsslen = ALIGN(bsslen + size, 8);
188 return sym - syms;
191 long o_mkundef(char *name)
193 Elf64_Sym *sym = put_sym(name);
194 sym->st_shndx = SHN_UNDEF;
195 return sym - syms;
198 long o_mkdat(char *name, char *buf, int len)
200 Elf64_Sym *sym = put_sym(name);
201 sym->st_shndx = SEC_DAT;
202 sym->st_value = datlen;
203 sym->st_size = len;
204 sym->st_info = ELF64_ST_INFO(name ? STB_GLOBAL : STB_LOCAL, STT_OBJECT);
205 memcpy(dat + datlen, buf, len);
206 datlen = ALIGN(datlen + len, 8);
207 return sym - syms;