tok: read '\08' as {'\0', '8'}
[neatcc.git] / out.c
bloba5571eb1d52a31f2391f08ea8f73cd2420a69e72
1 #include <elf.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include "out.h"
5 #include "gen.h"
7 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
9 #define MAXSYMS (1 << 12)
10 #define MAXREL (1 << 12)
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 /* simplifed 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[MAXSYMS];
48 static int nsyms = 1;
49 static char symstr[MAXSYMS * 8];
50 static int nsymstr = 1;
52 static Elf_Rel dsrels[MAXREL];
53 static int ndsrels;
54 static Elf_Rel rels[MAXREL];
55 static int nrels;
57 static int rel_type(int flags);
58 static void ehdr_init(Elf_Ehdr *ehdr);
60 static int symstr_add(char *name)
62 int len = strlen(name) + 1;
63 strcpy(symstr + nsymstr, name);
64 nsymstr += len;
65 return nsymstr - len;
68 static int sym_find(char *name)
70 int i;
71 for (i = 0; i < nsyms; i++)
72 if (!strcmp(name, symstr + syms[i].st_name))
73 return i;
74 return -1;
77 static Elf_Sym *put_sym(char *name)
79 int found = sym_find(name);
80 Elf_Sym *sym = found != -1 ? &syms[found] : &syms[nsyms++];
81 if (found >= 0)
82 return sym;
83 sym->st_name = symstr_add(name);
84 sym->st_shndx = SHN_UNDEF;
85 sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC);
86 return sym;
89 #define SYMLOCAL(i) (ELF_ST_BIND(syms[i].st_info) == STB_LOCAL)
91 static void mvrela(int *mv, Elf_Rel *rels, int nrels)
93 int i;
94 for (i = 0; i < nrels; i++) {
95 int sym = ELF_R_SYM(rels[i].r_info);
96 int type = ELF_R_TYPE(rels[i].r_info);
97 rels[i].r_info = ELF_R_INFO(mv[sym], type);
101 static int syms_sort(void)
103 int mv[MAXSYMS];
104 int i, j;
105 int glob_beg = 1;
106 for (i = 0; i < nsyms; i++)
107 mv[i] = i;
108 i = 1;
109 j = nsyms - 1;
110 while (1) {
111 Elf_Sym t;
112 while (i < j && SYMLOCAL(i))
113 i++;
114 while (j >= i && !SYMLOCAL(j))
115 j--;
116 if (i >= j)
117 break;
118 t = syms[j];
119 syms[j] = syms[i];
120 syms[i] = t;
121 mv[i] = j;
122 mv[j] = i;
124 glob_beg = j + 1;
125 mvrela(mv, rels, nrels);
126 mvrela(mv, dsrels, ndsrels);
127 return glob_beg;
130 void out_init(int flags)
134 void out_sym(char *name, int flags, int off, int len)
136 Elf_Sym *sym = put_sym(name);
137 int type = (flags & OUT_CS) ? STT_FUNC : STT_OBJECT;
138 int bind = (flags & OUT_GLOB) ? STB_GLOBAL : STB_LOCAL;
139 if (flags & OUT_CS)
140 sym->st_shndx = SEC_TEXT;
141 if (flags & OUT_DS)
142 sym->st_shndx = SEC_DAT;
143 if (flags & OUT_BSS)
144 sym->st_shndx = SEC_BSS;
145 sym->st_info = ELF_ST_INFO(bind, type);
146 sym->st_value = off;
147 sym->st_size = len;
150 static void out_csrel(int idx, int off, int flags)
152 Elf_Rel *r = &rels[nrels++];
153 r->r_offset = off;
154 r->r_info = ELF_R_INFO(idx, rel_type(flags));
157 static void out_dsrel(int idx, int off, int flags)
159 Elf_Rel *r = &dsrels[ndsrels++];
160 r->r_offset = off;
161 r->r_info = ELF_R_INFO(idx, rel_type(flags));
164 void out_rel(char *name, int flags, int off)
166 Elf_Sym *sym = put_sym(name);
167 int idx = sym - syms;
168 if (flags & OUT_DS)
169 out_dsrel(idx, off, flags);
170 else
171 out_csrel(idx, off, flags);
174 static int bss_len(void)
176 int len = 0;
177 int i;
178 for (i = 0; i < nsyms; i++) {
179 int end = syms[i].st_value + syms[i].st_size;
180 if (syms[i].st_shndx == SEC_BSS)
181 if (len < end)
182 len = end;
184 return len;
187 void out_write(int fd, char *cs, int cslen, char *ds, int dslen)
189 Elf_Shdr *text_shdr = &shdr[SEC_TEXT];
190 Elf_Shdr *rela_shdr = &shdr[SEC_REL];
191 Elf_Shdr *symstr_shdr = &shdr[SEC_SYMSTR];
192 Elf_Shdr *syms_shdr = &shdr[SEC_SYMS];
193 Elf_Shdr *dat_shdr = &shdr[SEC_DAT];
194 Elf_Shdr *datrel_shdr = &shdr[SEC_DATREL];
195 Elf_Shdr *bss_shdr = &shdr[SEC_BSS];
196 unsigned long offset = sizeof(ehdr);
198 /* workaround for the idiotic gnuld; use neatld instead! */
199 text_shdr->sh_name = symstr_add(".cs");
200 rela_shdr->sh_name = symstr_add(USERELA ? ".rela.cs" : ".rels.cs");
201 dat_shdr->sh_name = symstr_add(".ds");
202 datrel_shdr->sh_name = symstr_add(USERELA ? ".rela.ds" : ".rels.ds");
204 ehdr.e_ident[0] = 0x7f;
205 ehdr.e_ident[1] = 'E';
206 ehdr.e_ident[2] = 'L';
207 ehdr.e_ident[3] = 'F';
208 ehdr.e_ident[4] = LONGSZ == 8 ? ELFCLASS64 : ELFCLASS32;
209 ehdr.e_ident[5] = ELFDATA2LSB;
210 ehdr.e_ident[6] = EV_CURRENT;
211 ehdr.e_type = ET_REL;
212 ehdr_init(&ehdr);
213 ehdr.e_version = EV_CURRENT;
214 ehdr.e_ehsize = sizeof(ehdr);
215 ehdr.e_shentsize = sizeof(shdr[0]);
216 ehdr.e_shoff = offset;
217 ehdr.e_shnum = NSECS;
218 ehdr.e_shstrndx = SEC_SYMSTR;
219 offset += sizeof(shdr[0]) * NSECS;
221 text_shdr->sh_type = SHT_PROGBITS;
222 text_shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
223 text_shdr->sh_offset = offset;
224 text_shdr->sh_size = cslen;
225 text_shdr->sh_entsize = 1;
226 text_shdr->sh_addralign = OUT_ALIGNMENT;
227 offset += text_shdr->sh_size;
229 rela_shdr->sh_type = USERELA ? SHT_RELA : SHT_REL;
230 rela_shdr->sh_link = SEC_SYMS;
231 rela_shdr->sh_info = SEC_TEXT;
232 rela_shdr->sh_offset = offset;
233 rela_shdr->sh_size = nrels * sizeof(rels[0]);
234 rela_shdr->sh_entsize = sizeof(rels[0]);
235 offset += rela_shdr->sh_size;
237 syms_shdr->sh_type = SHT_SYMTAB;
238 syms_shdr->sh_offset = offset;
239 syms_shdr->sh_size = nsyms * sizeof(syms[0]);
240 syms_shdr->sh_entsize = sizeof(syms[0]);
241 syms_shdr->sh_link = SEC_SYMSTR;
242 syms_shdr->sh_info = syms_sort();
243 offset += syms_shdr->sh_size;
245 dat_shdr->sh_type = SHT_PROGBITS;
246 dat_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
247 dat_shdr->sh_offset = offset;
248 dat_shdr->sh_size = dslen;
249 dat_shdr->sh_entsize = 1;
250 dat_shdr->sh_addralign = OUT_ALIGNMENT;
251 offset += dat_shdr->sh_size;
253 datrel_shdr->sh_type = USERELA ? SHT_RELA : SHT_REL;
254 datrel_shdr->sh_offset = offset;
255 datrel_shdr->sh_size = ndsrels * sizeof(dsrels[0]);
256 datrel_shdr->sh_entsize = sizeof(dsrels[0]);
257 datrel_shdr->sh_link = SEC_SYMS;
258 datrel_shdr->sh_info = SEC_DAT;
259 offset += datrel_shdr->sh_size;
261 bss_shdr->sh_type = SHT_NOBITS;
262 bss_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
263 bss_shdr->sh_offset = offset;
264 bss_shdr->sh_size = bss_len();
265 bss_shdr->sh_entsize = 1;
266 bss_shdr->sh_addralign = OUT_ALIGNMENT;
268 symstr_shdr->sh_type = SHT_STRTAB;
269 symstr_shdr->sh_offset = offset;
270 symstr_shdr->sh_size = nsymstr;
271 symstr_shdr->sh_entsize = 1;
272 offset += symstr_shdr->sh_size;
274 write(fd, &ehdr, sizeof(ehdr));
275 write(fd, shdr, NSECS * sizeof(shdr[0]));
276 write(fd, cs, cslen);
277 write(fd, rels, nrels * sizeof(rels[0]));
278 write(fd, syms, nsyms * sizeof(syms[0]));
279 write(fd, ds, dslen);
280 write(fd, dsrels, ndsrels * sizeof(dsrels[0]));
281 write(fd, symstr, nsymstr);
284 /* architecture dependent functions */
286 #ifdef NEATCC_ARM
287 static void ehdr_init(Elf_Ehdr *ehdr)
289 ehdr->e_machine = EM_ARM;
290 ehdr->e_flags = EF_ARM_EABI_VER4;
293 static int rel_type(int flags)
295 if (flags & OUT_RL24)
296 return R_ARM_PC24;
297 return flags & OUT_RLREL ? R_ARM_REL32 : R_ARM_ABS32;
300 #endif
302 #ifdef NEATCC_X64
303 static void ehdr_init(Elf_Ehdr *ehdr)
305 ehdr->e_machine = EM_X86_64;
308 static int rel_type(int flags)
310 if (flags & OUT_RLREL)
311 return R_X86_64_PC32;
312 if (flags & OUT_RL32)
313 return flags & OUT_RLSX ? R_X86_64_32S : R_X86_64_32;
314 return R_X86_64_64;
316 #endif
318 #ifdef NEATCC_X86
319 static void ehdr_init(Elf_Ehdr *ehdr)
321 ehdr->e_machine = EM_386;
324 static int rel_type(int flags)
326 return flags & OUT_RLREL ? R_386_PC32 : R_386_32;
328 #endif