cpp: use a simple hash table instead of tab struct
[neatcc.git] / out.c
blobd1dbd3e4ab8dd6034188b51e84fd5db83b16f4f6
1 #include <elf.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include "gen.h"
5 #include "ncc.h"
6 #include "out.h"
8 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
10 #define SEC_TEXT 1
11 #define SEC_REL 2
12 #define SEC_SYMS 3
13 #define SEC_SYMSTR 4
14 #define SEC_DAT 5
15 #define SEC_DATREL 6
16 #define SEC_BSS 7
17 #define NSECS 8
19 /* simplifed elf struct and macro names */
20 #if LONGSZ == 8
21 # define USERELA 1
22 # define Elf_Ehdr Elf64_Ehdr
23 # define Elf_Shdr Elf64_Shdr
24 # define Elf_Sym Elf64_Sym
25 # define Elf_Rel Elf64_Rela
26 # define ELF_ST_INFO ELF64_ST_INFO
27 # define ELF_ST_BIND ELF64_ST_BIND
28 # define ELF_R_SYM ELF64_R_SYM
29 # define ELF_R_TYPE ELF64_R_TYPE
30 # define ELF_R_INFO ELF64_R_INFO
31 #else
32 # define USERELA 0
33 # define Elf_Ehdr Elf32_Ehdr
34 # define Elf_Shdr Elf32_Shdr
35 # define Elf_Sym Elf32_Sym
36 # define Elf_Rel Elf32_Rel
37 # define ELF_ST_INFO ELF32_ST_INFO
38 # define ELF_ST_BIND ELF32_ST_BIND
39 # define ELF_R_SYM ELF32_R_SYM
40 # define ELF_R_TYPE ELF32_R_TYPE
41 # define ELF_R_INFO ELF32_R_INFO
42 #endif
44 static Elf_Ehdr ehdr;
45 static Elf_Shdr shdr[NSECS];
46 static Elf_Sym syms[NSYMS];
47 static int nsyms = 1;
48 static char symstr[NSYMS * 8];
49 static int nsymstr = 1;
51 static Elf_Rel dsrels[NREL];
52 static int ndsrels;
53 static Elf_Rel rels[NREL];
54 static int nrels;
56 static int rel_type(int flags);
57 static void ehdr_init(Elf_Ehdr *ehdr);
59 static int symstr_add(char *name)
61 int len = strlen(name) + 1;
62 strcpy(symstr + nsymstr, name);
63 nsymstr += len;
64 return nsymstr - len;
67 static int sym_find(char *name)
69 int i;
70 for (i = 0; i < nsyms; i++)
71 if (!strcmp(name, symstr + syms[i].st_name))
72 return i;
73 return -1;
76 static Elf_Sym *put_sym(char *name)
78 int found = sym_find(name);
79 Elf_Sym *sym = found != -1 ? &syms[found] : &syms[nsyms++];
80 if (found >= 0)
81 return sym;
82 sym->st_name = symstr_add(name);
83 sym->st_shndx = SHN_UNDEF;
84 sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC);
85 return sym;
88 #define SYMLOCAL(i) (ELF_ST_BIND(syms[i].st_info) == STB_LOCAL)
90 static void mvrela(int *mv, Elf_Rel *rels, int nrels)
92 int i;
93 for (i = 0; i < nrels; i++) {
94 int sym = ELF_R_SYM(rels[i].r_info);
95 int type = ELF_R_TYPE(rels[i].r_info);
96 rels[i].r_info = ELF_R_INFO(mv[sym], type);
100 static int syms_sort(void)
102 int mv[NSYMS];
103 int i, j;
104 int glob_beg = 1;
105 for (i = 0; i < nsyms; i++)
106 mv[i] = i;
107 i = 1;
108 j = nsyms - 1;
109 while (1) {
110 Elf_Sym t;
111 while (i < j && SYMLOCAL(i))
112 i++;
113 while (j >= i && !SYMLOCAL(j))
114 j--;
115 if (i >= j)
116 break;
117 t = syms[j];
118 syms[j] = syms[i];
119 syms[i] = t;
120 mv[i] = j;
121 mv[j] = i;
123 glob_beg = j + 1;
124 mvrela(mv, rels, nrels);
125 mvrela(mv, dsrels, ndsrels);
126 return glob_beg;
129 void out_init(int flags)
133 void out_sym(char *name, int flags, int off, int len)
135 Elf_Sym *sym = put_sym(name);
136 int type = (flags & OUT_CS) ? STT_FUNC : STT_OBJECT;
137 int bind = (flags & OUT_GLOB) ? STB_GLOBAL : STB_LOCAL;
138 if (flags & OUT_CS)
139 sym->st_shndx = SEC_TEXT;
140 if (flags & OUT_DS)
141 sym->st_shndx = SEC_DAT;
142 if (flags & OUT_BSS)
143 sym->st_shndx = SEC_BSS;
144 sym->st_info = ELF_ST_INFO(bind, type);
145 sym->st_value = off;
146 sym->st_size = len;
149 static void out_csrel(int idx, int off, int flags)
151 Elf_Rel *r = &rels[nrels++];
152 r->r_offset = off;
153 r->r_info = ELF_R_INFO(idx, rel_type(flags));
156 static void out_dsrel(int idx, int off, int flags)
158 Elf_Rel *r = &dsrels[ndsrels++];
159 r->r_offset = off;
160 r->r_info = ELF_R_INFO(idx, rel_type(flags));
163 void out_rel(char *name, int flags, int off)
165 Elf_Sym *sym = put_sym(name);
166 int idx = sym - syms;
167 if (flags & OUT_DS)
168 out_dsrel(idx, off, flags);
169 else
170 out_csrel(idx, off, flags);
173 static int bss_len(void)
175 int len = 0;
176 int i;
177 for (i = 0; i < nsyms; i++) {
178 int end = syms[i].st_value + syms[i].st_size;
179 if (syms[i].st_shndx == SEC_BSS)
180 if (len < end)
181 len = end;
183 return len;
186 void out_write(int fd, char *cs, int cslen, char *ds, int dslen)
188 Elf_Shdr *text_shdr = &shdr[SEC_TEXT];
189 Elf_Shdr *rela_shdr = &shdr[SEC_REL];
190 Elf_Shdr *symstr_shdr = &shdr[SEC_SYMSTR];
191 Elf_Shdr *syms_shdr = &shdr[SEC_SYMS];
192 Elf_Shdr *dat_shdr = &shdr[SEC_DAT];
193 Elf_Shdr *datrel_shdr = &shdr[SEC_DATREL];
194 Elf_Shdr *bss_shdr = &shdr[SEC_BSS];
195 unsigned long offset = sizeof(ehdr);
197 /* workaround for the idiotic gnuld; use neatld instead! */
198 text_shdr->sh_name = symstr_add(".cs");
199 rela_shdr->sh_name = symstr_add(USERELA ? ".rela.cs" : ".rels.cs");
200 dat_shdr->sh_name = symstr_add(".ds");
201 datrel_shdr->sh_name = symstr_add(USERELA ? ".rela.ds" : ".rels.ds");
203 ehdr.e_ident[0] = 0x7f;
204 ehdr.e_ident[1] = 'E';
205 ehdr.e_ident[2] = 'L';
206 ehdr.e_ident[3] = 'F';
207 ehdr.e_ident[4] = LONGSZ == 8 ? ELFCLASS64 : ELFCLASS32;
208 ehdr.e_ident[5] = ELFDATA2LSB;
209 ehdr.e_ident[6] = EV_CURRENT;
210 ehdr.e_type = ET_REL;
211 ehdr_init(&ehdr);
212 ehdr.e_version = EV_CURRENT;
213 ehdr.e_ehsize = sizeof(ehdr);
214 ehdr.e_shentsize = sizeof(shdr[0]);
215 ehdr.e_shoff = offset;
216 ehdr.e_shnum = NSECS;
217 ehdr.e_shstrndx = SEC_SYMSTR;
218 offset += sizeof(shdr[0]) * NSECS;
220 text_shdr->sh_type = SHT_PROGBITS;
221 text_shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
222 text_shdr->sh_offset = offset;
223 text_shdr->sh_size = cslen;
224 text_shdr->sh_entsize = 1;
225 text_shdr->sh_addralign = OUT_ALIGNMENT;
226 offset += text_shdr->sh_size;
228 rela_shdr->sh_type = USERELA ? SHT_RELA : SHT_REL;
229 rela_shdr->sh_link = SEC_SYMS;
230 rela_shdr->sh_info = SEC_TEXT;
231 rela_shdr->sh_offset = offset;
232 rela_shdr->sh_size = nrels * sizeof(rels[0]);
233 rela_shdr->sh_entsize = sizeof(rels[0]);
234 offset += rela_shdr->sh_size;
236 syms_shdr->sh_type = SHT_SYMTAB;
237 syms_shdr->sh_offset = offset;
238 syms_shdr->sh_size = nsyms * sizeof(syms[0]);
239 syms_shdr->sh_entsize = sizeof(syms[0]);
240 syms_shdr->sh_link = SEC_SYMSTR;
241 syms_shdr->sh_info = syms_sort();
242 offset += syms_shdr->sh_size;
244 dat_shdr->sh_type = SHT_PROGBITS;
245 dat_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
246 dat_shdr->sh_offset = offset;
247 dat_shdr->sh_size = dslen;
248 dat_shdr->sh_entsize = 1;
249 dat_shdr->sh_addralign = OUT_ALIGNMENT;
250 offset += dat_shdr->sh_size;
252 datrel_shdr->sh_type = USERELA ? SHT_RELA : SHT_REL;
253 datrel_shdr->sh_offset = offset;
254 datrel_shdr->sh_size = ndsrels * sizeof(dsrels[0]);
255 datrel_shdr->sh_entsize = sizeof(dsrels[0]);
256 datrel_shdr->sh_link = SEC_SYMS;
257 datrel_shdr->sh_info = SEC_DAT;
258 offset += datrel_shdr->sh_size;
260 bss_shdr->sh_type = SHT_NOBITS;
261 bss_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
262 bss_shdr->sh_offset = offset;
263 bss_shdr->sh_size = bss_len();
264 bss_shdr->sh_entsize = 1;
265 bss_shdr->sh_addralign = OUT_ALIGNMENT;
267 symstr_shdr->sh_type = SHT_STRTAB;
268 symstr_shdr->sh_offset = offset;
269 symstr_shdr->sh_size = nsymstr;
270 symstr_shdr->sh_entsize = 1;
271 offset += symstr_shdr->sh_size;
273 write(fd, &ehdr, sizeof(ehdr));
274 write(fd, shdr, NSECS * sizeof(shdr[0]));
275 write(fd, cs, cslen);
276 write(fd, rels, nrels * sizeof(rels[0]));
277 write(fd, syms, nsyms * sizeof(syms[0]));
278 write(fd, ds, dslen);
279 write(fd, dsrels, ndsrels * sizeof(dsrels[0]));
280 write(fd, symstr, nsymstr);
283 /* architecture dependent functions */
285 #ifdef NEATCC_ARM
286 static void ehdr_init(Elf_Ehdr *ehdr)
288 ehdr->e_machine = EM_ARM;
289 ehdr->e_flags = EF_ARM_EABI_VER4;
292 static int rel_type(int flags)
294 if (flags & OUT_RL24)
295 return R_ARM_PC24;
296 return flags & OUT_RLREL ? R_ARM_REL32 : R_ARM_ABS32;
299 #endif
301 #ifdef NEATCC_X64
302 static void ehdr_init(Elf_Ehdr *ehdr)
304 ehdr->e_machine = EM_X86_64;
307 static int rel_type(int flags)
309 if (flags & OUT_RLREL)
310 return R_X86_64_PC32;
311 if (flags & OUT_RL32)
312 return flags & OUT_RLSX ? R_X86_64_32S : R_X86_64_32;
313 return R_X86_64_64;
315 #endif
317 #ifdef NEATCC_X86
318 static void ehdr_init(Elf_Ehdr *ehdr)
320 ehdr->e_machine = EM_386;
323 static int rel_type(int flags)
325 return flags & OUT_RLREL ? R_386_PC32 : R_386_32;
327 #endif