gen: fix ignoring regop1() return value
[neatcc/cc.git] / out.c
blob3b9d2d6f5c21a362e53cacef649f29b3b1966edc
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 << 10)
9 #define MAXSYMS (1 << 12)
10 #define MAXRELA (1 << 12)
11 #define SEC_SYMS 1
12 #define SEC_SYMSTR 2
13 #define SEC_DAT 3
14 #define SEC_DATRELA 4
15 #define SEC_BSS 5
16 #define SEC_BEG 6
18 static Elf64_Ehdr ehdr;
19 static Elf64_Shdr shdr[MAXSECS];
20 static int nshdr = SEC_BEG;
21 static Elf64_Sym syms[MAXSYMS];
22 static int nsyms = 1;
23 static char symstr[MAXSYMS * 8];
24 static int nsymstr = 1;
25 static int bsslen;
26 static char dat[SECSIZE];
27 static int datlen;
28 static Elf64_Rela datrela[MAXRELA];
29 static int ndatrela;
31 static struct sec {
32 char buf[SECSIZE];
33 int len;
34 Elf64_Sym *sym;
35 Elf64_Rela rela[MAXRELA];
36 int nrela;
37 Elf64_Shdr *sec_shdr;
38 Elf64_Shdr *rel_shdr;
39 } secs[MAXSECS];
40 static int nsecs;
41 static struct sec *sec;
43 static char *putstr(char *s, char *r)
45 while (*r)
46 *s++ = *r++;
47 *s++ = '\0';
48 return s;
51 static int sym_find(char *name)
53 int i;
54 for (i = 0; i < nsyms; i++)
55 if (!strcmp(name, symstr + syms[i].st_name))
56 return i;
57 return -1;
60 static Elf64_Sym *put_sym(char *name)
62 int found = name ? sym_find(name) : -1;
63 Elf64_Sym *sym = found != -1 ? &syms[found] : &syms[nsyms++];
64 if (!name)
65 sym->st_name = 0;
66 if (name && found == -1) {
67 sym->st_name = nsymstr;
68 nsymstr = putstr(symstr + nsymstr, name) - symstr;
70 return sym;
73 #define S_BIND(global) ((global) ? STB_GLOBAL : STB_LOCAL)
75 long out_func_beg(char *name, int global)
77 sec = &secs[nsecs++];
78 sec->sym = put_sym(name);
79 sec->sym->st_shndx = nshdr;
80 sec->sym->st_info = ELF64_ST_INFO(S_BIND(global), STT_FUNC);
81 sec->sec_shdr = &shdr[nshdr++];
82 sec->rel_shdr = &shdr[nshdr++];
83 sec->rel_shdr->sh_link = SEC_SYMS;
84 sec->rel_shdr->sh_info = sec->sec_shdr - shdr;
85 return sec->sym - syms;
88 void out_func_end(char *buf, int len)
90 memcpy(sec->buf, buf, len);
91 sec->len = len;
92 sec->sym->st_size = len;
95 void out_rela(long addr, int off, int rel)
97 Elf64_Rela *rela = &sec->rela[sec->nrela++];
98 rela->r_offset = off;
99 rela->r_info = ELF64_R_INFO(addr, rel ? R_X86_64_PC32 : R_X86_64_32);
102 void out_datrela(long addr, long dataddr, int off)
104 Elf64_Rela *rela = &datrela[ndatrela++];
105 rela->r_offset = syms[dataddr].st_value + off;
106 rela->r_info = ELF64_R_INFO(addr, R_X86_64_32);
109 #define SYMLOCAL(i) (ELF64_ST_BIND(syms[i].st_info) & STB_LOCAL)
111 static void mvrela(int *mv, Elf64_Rela *rela, int nrela)
113 int i;
114 for (i = 0; i < nrela; i++) {
115 int sym = ELF64_R_SYM(rela[i].r_info);
116 int type = ELF64_R_TYPE(rela[i].r_info);
117 rela[i].r_info = ELF64_R_INFO(mv[sym], type);
121 static int syms_sort(void)
123 int mv[MAXSYMS];
124 int i, j;
125 int glob_beg;
126 for (i = 0; i < nsyms; i++)
127 mv[i] = i;
128 i = 1;
129 j = nsyms - 1;
130 while (1) {
131 Elf64_Sym t;
132 while (j > i && !SYMLOCAL(j))
133 j--;
134 while (i < j && SYMLOCAL(i))
135 i++;
136 if (i >= j)
137 break;
138 t = syms[j];
139 syms[i] = syms[j];
140 syms[i] = t;
141 mv[i] = j;
142 mv[j] = i;
144 glob_beg = i;
145 for (i = 0; i < nsecs; i++)
146 mvrela(mv, sec[i].rela, sec[i].nrela);
147 mvrela(mv, datrela, ndatrela);
148 return glob_beg;
151 void out_write(int fd)
153 Elf64_Shdr *symstr_shdr = &shdr[SEC_SYMSTR];
154 Elf64_Shdr *syms_shdr = &shdr[SEC_SYMS];
155 Elf64_Shdr *dat_shdr = &shdr[SEC_DAT];
156 Elf64_Shdr *datrela_shdr = &shdr[SEC_DATRELA];
157 Elf64_Shdr *bss_shdr = &shdr[SEC_BSS];
158 unsigned long offset = sizeof(ehdr);
159 int i;
161 ehdr.e_ident[0] = 0x7f;
162 ehdr.e_ident[1] = 'E';
163 ehdr.e_ident[2] = 'L';
164 ehdr.e_ident[3] = 'F';
165 ehdr.e_ident[4] = ELFCLASS64;
166 ehdr.e_ident[5] = ELFDATA2LSB;
167 ehdr.e_ident[6] = EV_CURRENT;
168 ehdr.e_type = ET_REL;
169 ehdr.e_machine = EM_X86_64;
170 ehdr.e_version = EV_CURRENT;
171 ehdr.e_ehsize = sizeof(ehdr);
172 ehdr.e_shentsize = sizeof(shdr[0]);
173 ehdr.e_shoff = offset;
174 ehdr.e_shnum = nshdr;
175 ehdr.e_shstrndx = SEC_SYMSTR;
176 offset += sizeof(shdr[0]) * nshdr;
178 syms_shdr->sh_type = SHT_SYMTAB;
179 syms_shdr->sh_offset = offset;
180 syms_shdr->sh_size = nsyms * sizeof(syms[0]);
181 syms_shdr->sh_entsize = sizeof(syms[0]);
182 syms_shdr->sh_link = SEC_SYMSTR;
183 syms_shdr->sh_info = syms_sort();
184 offset += syms_shdr->sh_size;
186 dat_shdr->sh_type = SHT_PROGBITS;
187 dat_shdr->sh_flags = SHF_WRITE;
188 dat_shdr->sh_offset = offset;
189 dat_shdr->sh_size = datlen;
190 dat_shdr->sh_entsize = 1;
191 dat_shdr->sh_addralign = 8;
192 offset += dat_shdr->sh_size;
194 datrela_shdr->sh_type = SHT_RELA;
195 datrela_shdr->sh_offset = offset;
196 datrela_shdr->sh_size = ndatrela * sizeof(datrela[0]);
197 datrela_shdr->sh_entsize = sizeof(datrela[0]);
198 datrela_shdr->sh_link = SEC_SYMS;
199 datrela_shdr->sh_info = SEC_DAT;
200 offset += datrela_shdr->sh_size;
202 bss_shdr->sh_type = SHT_NOBITS;
203 bss_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
204 bss_shdr->sh_offset = offset;
205 bss_shdr->sh_size = bsslen;
206 bss_shdr->sh_entsize = 1;
207 bss_shdr->sh_addralign = 8;
209 symstr_shdr->sh_type = SHT_STRTAB;
210 symstr_shdr->sh_offset = offset;
211 symstr_shdr->sh_size = nsymstr;
212 symstr_shdr->sh_entsize = 1;
213 offset += symstr_shdr->sh_size;
215 for (i = 0; i < nsecs; i++) {
216 struct sec *sec = &secs[i];
218 sec->sec_shdr->sh_type = SHT_PROGBITS;
219 sec->sec_shdr->sh_flags = SHF_EXECINSTR;
220 sec->sec_shdr->sh_offset = offset;
221 sec->sec_shdr->sh_size = sec->len;
222 sec->sec_shdr->sh_entsize = 1;
223 offset += sec->sec_shdr->sh_size;
225 sec->rel_shdr->sh_type = SHT_RELA;
226 sec->rel_shdr->sh_offset = offset;
227 sec->rel_shdr->sh_size = sec->nrela * sizeof(sec->rela[0]);
228 sec->rel_shdr->sh_entsize = sizeof(sec->rela[0]);
229 offset += sec->rel_shdr->sh_size;
232 write(fd, &ehdr, sizeof(ehdr));
233 write(fd, shdr, sizeof(shdr[0]) * nshdr);
234 write(fd, syms, sizeof(syms[0]) * nsyms);
235 write(fd, dat, datlen);
236 write(fd, datrela, ndatrela * sizeof(datrela[0]));
237 write(fd, symstr, nsymstr);
238 for (i = 0; i < nsecs; i++) {
239 struct sec *sec = &secs[i];
240 write(fd, sec->buf, sec->len);
241 write(fd, sec->rela, sec->nrela * sizeof(sec->rela[0]));
245 long out_mkvar(char *name, int size, int global)
247 Elf64_Sym *sym = put_sym(name);
248 sym->st_shndx = SEC_BSS;
249 sym->st_value = bsslen;
250 sym->st_size = size;
251 sym->st_info = ELF64_ST_INFO(S_BIND(global), STT_OBJECT);
252 bsslen = ALIGN(bsslen + size, 8);
253 return sym - syms;
256 long out_mkundef(char *name, int sz)
258 Elf64_Sym *sym = put_sym(name);
259 sym->st_shndx = SHN_UNDEF;
260 sym->st_info = ELF64_ST_INFO(STB_GLOBAL, sz ? STT_OBJECT : STT_FUNC);
261 sym->st_size = sz;
262 return sym - syms;
265 long out_mkdat(char *name, char *buf, int len, int global)
267 Elf64_Sym *sym = put_sym(name);
268 sym->st_shndx = SEC_DAT;
269 sym->st_value = datlen;
270 sym->st_size = len;
271 sym->st_info = ELF64_ST_INFO(S_BIND(global), STT_OBJECT);
272 if (buf)
273 memcpy(dat + datlen, buf, len);
274 else
275 memset(dat + datlen, 0, len);
276 datlen = ALIGN(datlen + len, 8);
277 return sym - syms;
280 void out_datcpy(long addr, int off, char *buf, int len)
282 memcpy(dat + syms[addr].st_value + off, buf, len);