x64: use short jumps when possible
[neatcc.git] / out.c
blob4b05ef3ce9b3be7e0558dd5ccbef8d5e847d95f2
1 /* neatcc ELF object generation */
2 #include <elf.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include "ncc.h"
9 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
11 #define SEC_TEXT 1
12 #define SEC_REL 2
13 #define SEC_SYMS 3
14 #define SEC_SYMSTR 4
15 #define SEC_DAT 5
16 #define SEC_DATREL 6
17 #define SEC_BSS 7
18 #define NSECS 8
20 /* simplified elf struct and macro names */
21 #if LONGSZ == 8
22 # define USERELA 1
23 # define Elf_Ehdr Elf64_Ehdr
24 # define Elf_Shdr Elf64_Shdr
25 # define Elf_Sym Elf64_Sym
26 # define Elf_Rel Elf64_Rela
27 # define ELF_ST_INFO ELF64_ST_INFO
28 # define ELF_ST_BIND ELF64_ST_BIND
29 # define ELF_R_SYM ELF64_R_SYM
30 # define ELF_R_TYPE ELF64_R_TYPE
31 # define ELF_R_INFO ELF64_R_INFO
32 #else
33 # define USERELA 0
34 # define Elf_Ehdr Elf32_Ehdr
35 # define Elf_Shdr Elf32_Shdr
36 # define Elf_Sym Elf32_Sym
37 # define Elf_Rel Elf32_Rel
38 # define ELF_ST_INFO ELF32_ST_INFO
39 # define ELF_ST_BIND ELF32_ST_BIND
40 # define ELF_R_SYM ELF32_R_SYM
41 # define ELF_R_TYPE ELF32_R_TYPE
42 # define ELF_R_INFO ELF32_R_INFO
43 #endif
45 static Elf_Ehdr ehdr;
46 static Elf_Shdr shdr[NSECS];
47 static Elf_Sym *syms;
48 static long syms_n, syms_sz;
49 static char *symstr;
50 static long symstr_n, symstr_sz;
52 static Elf_Rel *dsrel;
53 static long dsrel_n, dsrel_sz;
54 static Elf_Rel *csrel;
55 static long csrel_n, csrel_sz;
57 void err(char *msg, ...);
58 static int rel_type(int flags);
59 static void ehdr_init(Elf_Ehdr *ehdr);
61 static long symstr_add(char *name)
63 long len = strlen(name) + 1;
64 if (symstr_n + len >= symstr_sz) {
65 symstr_sz = MAX(512, symstr_sz * 2);
66 symstr = mextend(symstr, symstr_n, symstr_sz, sizeof(symstr[0]));
68 strcpy(symstr + symstr_n, name);
69 symstr_n += len;
70 return symstr_n - len;
73 static long sym_find(char *name)
75 int i;
76 for (i = 0; i < syms_n; i++)
77 if (!strcmp(name, symstr + syms[i].st_name))
78 return i;
79 return -1;
82 static Elf_Sym *put_sym(char *name)
84 long found = sym_find(name);
85 Elf_Sym *sym;
86 if (found >= 0)
87 return &syms[found];
88 if (syms_n >= syms_sz) {
89 syms_sz = MAX(128, syms_sz * 2);
90 syms = mextend(syms, syms_n, syms_sz, sizeof(syms[0]));
92 sym = &syms[syms_n++];
93 sym->st_name = symstr_add(name);
94 sym->st_shndx = SHN_UNDEF;
95 sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC);
96 return sym;
99 #define SYMLOCAL(i) (ELF_ST_BIND(syms[i].st_info) == STB_LOCAL)
101 static void mvrela(long *mv, Elf_Rel *rels, long n)
103 long i;
104 for (i = 0; i < n; i++) {
105 int sym = ELF_R_SYM(rels[i].r_info);
106 int type = ELF_R_TYPE(rels[i].r_info);
107 rels[i].r_info = ELF_R_INFO(mv[sym], type);
111 static int syms_sort(void)
113 long *mv;
114 int i, j;
115 int glob_beg = 1;
116 mv = malloc(syms_n * sizeof(mv[0]));
117 for (i = 0; i < syms_n; i++)
118 mv[i] = i;
119 i = 1;
120 j = syms_n - 1;
121 while (1) {
122 Elf_Sym t;
123 while (i < j && SYMLOCAL(i))
124 i++;
125 while (j >= i && !SYMLOCAL(j))
126 j--;
127 if (i >= j)
128 break;
129 t = syms[j];
130 syms[j] = syms[i];
131 syms[i] = t;
132 mv[i] = j;
133 mv[j] = i;
135 glob_beg = j + 1;
136 mvrela(mv, csrel, csrel_n);
137 mvrela(mv, dsrel, dsrel_n);
138 free(mv);
139 return glob_beg;
142 void out_init(long flags)
144 put_sym("");
147 /* return a symbol identifier */
148 void out_def(char *name, long flags, long off, long len)
150 Elf_Sym *sym = put_sym(name);
151 int type = (flags & OUT_CS) ? STT_FUNC : STT_OBJECT;
152 int bind = (flags & OUT_GLOB) ? STB_GLOBAL : STB_LOCAL;
153 if (flags & OUT_CS)
154 sym->st_shndx = SEC_TEXT;
155 if (flags & OUT_DS)
156 sym->st_shndx = SEC_DAT;
157 if (flags & OUT_BSS)
158 sym->st_shndx = SEC_BSS;
159 sym->st_info = ELF_ST_INFO(bind, type);
160 sym->st_value = off;
161 sym->st_size = len;
164 long out_sym(char *name)
166 return put_sym(name) - syms;
169 static void out_csrel(long idx, long off, int flags)
171 Elf_Rel *r;
172 if (csrel_n >= csrel_sz) {
173 csrel_sz = MAX(128, csrel_sz * 2);
174 csrel = mextend(csrel, csrel_n, csrel_sz, sizeof(csrel[0]));
176 r = &csrel[csrel_n++];
177 r->r_offset = off;
178 r->r_info = ELF_R_INFO(idx, rel_type(flags));
181 static void out_dsrel(long idx, long off, int flags)
183 Elf_Rel *r;
184 if (dsrel_n >= dsrel_sz) {
185 dsrel_sz = MAX(128, dsrel_sz * 2);
186 dsrel = mextend(dsrel, dsrel_n, dsrel_sz, sizeof(dsrel[0]));
188 r = &dsrel[dsrel_n++];
189 r->r_offset = off;
190 r->r_info = ELF_R_INFO(idx, rel_type(flags));
193 void out_rel(long idx, long flags, long off)
195 if (flags & OUT_DS)
196 out_dsrel(idx, off, flags);
197 else
198 out_csrel(idx, off, flags);
201 static long bss_len(void)
203 long len = 0;
204 int i;
205 for (i = 0; i < syms_n; i++) {
206 long end = syms[i].st_value + syms[i].st_size;
207 if (syms[i].st_shndx == SEC_BSS)
208 if (len < end)
209 len = end;
211 return len;
214 void out_write(int fd, char *cs, long cslen, char *ds, long dslen)
216 Elf_Shdr *text_shdr = &shdr[SEC_TEXT];
217 Elf_Shdr *rela_shdr = &shdr[SEC_REL];
218 Elf_Shdr *symstr_shdr = &shdr[SEC_SYMSTR];
219 Elf_Shdr *syms_shdr = &shdr[SEC_SYMS];
220 Elf_Shdr *dat_shdr = &shdr[SEC_DAT];
221 Elf_Shdr *datrel_shdr = &shdr[SEC_DATREL];
222 Elf_Shdr *bss_shdr = &shdr[SEC_BSS];
223 unsigned long offset = sizeof(ehdr);
225 /* workaround for the idiotic gnuld; use neatld instead! */
226 text_shdr->sh_name = symstr_add(".cs");
227 rela_shdr->sh_name = symstr_add(USERELA ? ".rela.cs" : ".rels.cs");
228 dat_shdr->sh_name = symstr_add(".ds");
229 datrel_shdr->sh_name = symstr_add(USERELA ? ".rela.ds" : ".rels.ds");
231 ehdr.e_ident[0] = 0x7f;
232 ehdr.e_ident[1] = 'E';
233 ehdr.e_ident[2] = 'L';
234 ehdr.e_ident[3] = 'F';
235 ehdr.e_ident[4] = LONGSZ == 8 ? ELFCLASS64 : ELFCLASS32;
236 ehdr.e_ident[5] = ELFDATA2LSB;
237 ehdr.e_ident[6] = EV_CURRENT;
238 ehdr.e_type = ET_REL;
239 ehdr_init(&ehdr);
240 ehdr.e_version = EV_CURRENT;
241 ehdr.e_ehsize = sizeof(ehdr);
242 ehdr.e_shentsize = sizeof(shdr[0]);
243 ehdr.e_shoff = offset;
244 ehdr.e_shnum = NSECS;
245 ehdr.e_shstrndx = SEC_SYMSTR;
246 offset += sizeof(shdr[0]) * NSECS;
248 text_shdr->sh_type = SHT_PROGBITS;
249 text_shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
250 text_shdr->sh_offset = offset;
251 text_shdr->sh_size = cslen;
252 text_shdr->sh_entsize = 1;
253 text_shdr->sh_addralign = OUT_ALIGNMENT;
254 offset += text_shdr->sh_size;
256 rela_shdr->sh_type = USERELA ? SHT_RELA : SHT_REL;
257 rela_shdr->sh_link = SEC_SYMS;
258 rela_shdr->sh_info = SEC_TEXT;
259 rela_shdr->sh_offset = offset;
260 rela_shdr->sh_size = csrel_n * sizeof(csrel[0]);
261 rela_shdr->sh_entsize = sizeof(csrel[0]);
262 offset += rela_shdr->sh_size;
264 syms_shdr->sh_type = SHT_SYMTAB;
265 syms_shdr->sh_offset = offset;
266 syms_shdr->sh_size = syms_n * sizeof(syms[0]);
267 syms_shdr->sh_entsize = sizeof(syms[0]);
268 syms_shdr->sh_link = SEC_SYMSTR;
269 syms_shdr->sh_info = syms_sort();
270 offset += syms_shdr->sh_size;
272 dat_shdr->sh_type = SHT_PROGBITS;
273 dat_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
274 dat_shdr->sh_offset = offset;
275 dat_shdr->sh_size = dslen;
276 dat_shdr->sh_entsize = 1;
277 dat_shdr->sh_addralign = OUT_ALIGNMENT;
278 offset += dat_shdr->sh_size;
280 datrel_shdr->sh_type = USERELA ? SHT_RELA : SHT_REL;
281 datrel_shdr->sh_offset = offset;
282 datrel_shdr->sh_size = dsrel_n * sizeof(dsrel[0]);
283 datrel_shdr->sh_entsize = sizeof(dsrel[0]);
284 datrel_shdr->sh_link = SEC_SYMS;
285 datrel_shdr->sh_info = SEC_DAT;
286 offset += datrel_shdr->sh_size;
288 bss_shdr->sh_type = SHT_NOBITS;
289 bss_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
290 bss_shdr->sh_offset = offset;
291 bss_shdr->sh_size = bss_len();
292 bss_shdr->sh_entsize = 1;
293 bss_shdr->sh_addralign = OUT_ALIGNMENT;
295 symstr_shdr->sh_type = SHT_STRTAB;
296 symstr_shdr->sh_offset = offset;
297 symstr_shdr->sh_size = symstr_n;
298 symstr_shdr->sh_entsize = 1;
299 offset += symstr_shdr->sh_size;
301 write(fd, &ehdr, sizeof(ehdr));
302 write(fd, shdr, NSECS * sizeof(shdr[0]));
303 write(fd, cs, cslen);
304 write(fd, csrel, csrel_n * sizeof(csrel[0]));
305 write(fd, syms, syms_n * sizeof(syms[0]));
306 write(fd, ds, dslen);
307 write(fd, dsrel, dsrel_n * sizeof(dsrel[0]));
308 write(fd, symstr, symstr_n);
310 free(syms);
311 free(symstr);
312 free(csrel);
313 free(dsrel);
316 /* architecture dependent functions */
318 #ifdef NEATCC_ARM
319 static void ehdr_init(Elf_Ehdr *ehdr)
321 ehdr->e_machine = EM_ARM;
322 ehdr->e_flags = EF_ARM_EABI_VER4;
325 static int rel_type(int flags)
327 if (flags & OUT_RL24)
328 return R_ARM_PC24;
329 return flags & OUT_RLREL ? R_ARM_REL32 : R_ARM_ABS32;
332 #endif
334 #ifdef NEATCC_X64
335 static void ehdr_init(Elf_Ehdr *ehdr)
337 ehdr->e_machine = EM_X86_64;
340 static int rel_type(int flags)
342 if (flags & OUT_RLREL)
343 return R_X86_64_PC32;
344 if (flags & OUT_RL32)
345 return flags & OUT_RLSX ? R_X86_64_32S : R_X86_64_32;
346 return R_X86_64_64;
348 #endif
350 #ifdef NEATCC_X86
351 static void ehdr_init(Elf_Ehdr *ehdr)
353 ehdr->e_machine = EM_386;
356 static int rel_type(int flags)
358 return flags & OUT_RLREL ? R_386_PC32 : R_386_32;
360 #endif