out: exit if there is no room for more relocations or symbols
[neatcc.git] / out.c
blobe4a9ced999a32c9ab1e74cb7baf6a0d4eba27035
1 /* neatcc ELF object generation */
2 #include <elf.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include "gen.h"
6 #include "ncc.h"
7 #include "out.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[NSYMS];
48 static int nsyms = 1;
49 static char symstr[NSYMS * 8];
50 static int nsymstr = 1;
52 static Elf_Rel dsrels[NRELS];
53 static int ndsrels;
54 static Elf_Rel rels[NRELS];
55 static int nrels;
57 void err(char *msg, ...);
58 static int rel_type(int flags);
59 static void ehdr_init(Elf_Ehdr *ehdr);
61 static int symstr_add(char *name)
63 int len = strlen(name) + 1;
64 if (nsymstr + len >= sizeof(symstr))
65 err("nomem: NSYMS reached!\n");
66 strcpy(symstr + nsymstr, name);
67 nsymstr += len;
68 return nsymstr - len;
71 static int sym_find(char *name)
73 int i;
74 for (i = 0; i < nsyms; i++)
75 if (!strcmp(name, symstr + syms[i].st_name))
76 return i;
77 return -1;
80 static Elf_Sym *put_sym(char *name)
82 int found = sym_find(name);
83 Elf_Sym *sym = found != -1 ? &syms[found] : &syms[nsyms++];
84 if (found >= 0)
85 return sym;
86 if (nsyms >= NSYMS)
87 err("nomem: NSYMS reached!\n");
88 sym->st_name = symstr_add(name);
89 sym->st_shndx = SHN_UNDEF;
90 sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC);
91 return sym;
94 #define SYMLOCAL(i) (ELF_ST_BIND(syms[i].st_info) == STB_LOCAL)
96 static void mvrela(int *mv, Elf_Rel *rels, int nrels)
98 int i;
99 for (i = 0; i < nrels; i++) {
100 int sym = ELF_R_SYM(rels[i].r_info);
101 int type = ELF_R_TYPE(rels[i].r_info);
102 rels[i].r_info = ELF_R_INFO(mv[sym], type);
106 static int syms_sort(void)
108 int mv[NSYMS];
109 int i, j;
110 int glob_beg = 1;
111 for (i = 0; i < nsyms; i++)
112 mv[i] = i;
113 i = 1;
114 j = nsyms - 1;
115 while (1) {
116 Elf_Sym t;
117 while (i < j && SYMLOCAL(i))
118 i++;
119 while (j >= i && !SYMLOCAL(j))
120 j--;
121 if (i >= j)
122 break;
123 t = syms[j];
124 syms[j] = syms[i];
125 syms[i] = t;
126 mv[i] = j;
127 mv[j] = i;
129 glob_beg = j + 1;
130 mvrela(mv, rels, nrels);
131 mvrela(mv, dsrels, ndsrels);
132 return glob_beg;
135 void out_init(int flags)
139 void out_sym(char *name, int flags, int off, int len)
141 Elf_Sym *sym = put_sym(name);
142 int type = (flags & OUT_CS) ? STT_FUNC : STT_OBJECT;
143 int bind = (flags & OUT_GLOB) ? STB_GLOBAL : STB_LOCAL;
144 if (flags & OUT_CS)
145 sym->st_shndx = SEC_TEXT;
146 if (flags & OUT_DS)
147 sym->st_shndx = SEC_DAT;
148 if (flags & OUT_BSS)
149 sym->st_shndx = SEC_BSS;
150 sym->st_info = ELF_ST_INFO(bind, type);
151 sym->st_value = off;
152 sym->st_size = len;
155 static void out_csrel(int idx, int off, int flags)
157 Elf_Rel *r = &rels[nrels++];
158 if (nrels >= NRELS)
159 err("nomem: NRELS reached!\n");
160 r->r_offset = off;
161 r->r_info = ELF_R_INFO(idx, rel_type(flags));
164 static void out_dsrel(int idx, int off, int flags)
166 Elf_Rel *r = &dsrels[ndsrels++];
167 if (ndsrels >= NRELS)
168 err("nomem: NRELS reached!\n");
169 r->r_offset = off;
170 r->r_info = ELF_R_INFO(idx, rel_type(flags));
173 void out_rel(char *name, int flags, int off)
175 Elf_Sym *sym = put_sym(name);
176 int idx = sym - syms;
177 if (flags & OUT_DS)
178 out_dsrel(idx, off, flags);
179 else
180 out_csrel(idx, off, flags);
183 static int bss_len(void)
185 int len = 0;
186 int i;
187 for (i = 0; i < nsyms; i++) {
188 int end = syms[i].st_value + syms[i].st_size;
189 if (syms[i].st_shndx == SEC_BSS)
190 if (len < end)
191 len = end;
193 return len;
196 void out_write(int fd, char *cs, int cslen, char *ds, int dslen)
198 Elf_Shdr *text_shdr = &shdr[SEC_TEXT];
199 Elf_Shdr *rela_shdr = &shdr[SEC_REL];
200 Elf_Shdr *symstr_shdr = &shdr[SEC_SYMSTR];
201 Elf_Shdr *syms_shdr = &shdr[SEC_SYMS];
202 Elf_Shdr *dat_shdr = &shdr[SEC_DAT];
203 Elf_Shdr *datrel_shdr = &shdr[SEC_DATREL];
204 Elf_Shdr *bss_shdr = &shdr[SEC_BSS];
205 unsigned long offset = sizeof(ehdr);
207 /* workaround for the idiotic gnuld; use neatld instead! */
208 text_shdr->sh_name = symstr_add(".cs");
209 rela_shdr->sh_name = symstr_add(USERELA ? ".rela.cs" : ".rels.cs");
210 dat_shdr->sh_name = symstr_add(".ds");
211 datrel_shdr->sh_name = symstr_add(USERELA ? ".rela.ds" : ".rels.ds");
213 ehdr.e_ident[0] = 0x7f;
214 ehdr.e_ident[1] = 'E';
215 ehdr.e_ident[2] = 'L';
216 ehdr.e_ident[3] = 'F';
217 ehdr.e_ident[4] = LONGSZ == 8 ? ELFCLASS64 : ELFCLASS32;
218 ehdr.e_ident[5] = ELFDATA2LSB;
219 ehdr.e_ident[6] = EV_CURRENT;
220 ehdr.e_type = ET_REL;
221 ehdr_init(&ehdr);
222 ehdr.e_version = EV_CURRENT;
223 ehdr.e_ehsize = sizeof(ehdr);
224 ehdr.e_shentsize = sizeof(shdr[0]);
225 ehdr.e_shoff = offset;
226 ehdr.e_shnum = NSECS;
227 ehdr.e_shstrndx = SEC_SYMSTR;
228 offset += sizeof(shdr[0]) * NSECS;
230 text_shdr->sh_type = SHT_PROGBITS;
231 text_shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
232 text_shdr->sh_offset = offset;
233 text_shdr->sh_size = cslen;
234 text_shdr->sh_entsize = 1;
235 text_shdr->sh_addralign = OUT_ALIGNMENT;
236 offset += text_shdr->sh_size;
238 rela_shdr->sh_type = USERELA ? SHT_RELA : SHT_REL;
239 rela_shdr->sh_link = SEC_SYMS;
240 rela_shdr->sh_info = SEC_TEXT;
241 rela_shdr->sh_offset = offset;
242 rela_shdr->sh_size = nrels * sizeof(rels[0]);
243 rela_shdr->sh_entsize = sizeof(rels[0]);
244 offset += rela_shdr->sh_size;
246 syms_shdr->sh_type = SHT_SYMTAB;
247 syms_shdr->sh_offset = offset;
248 syms_shdr->sh_size = nsyms * sizeof(syms[0]);
249 syms_shdr->sh_entsize = sizeof(syms[0]);
250 syms_shdr->sh_link = SEC_SYMSTR;
251 syms_shdr->sh_info = syms_sort();
252 offset += syms_shdr->sh_size;
254 dat_shdr->sh_type = SHT_PROGBITS;
255 dat_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
256 dat_shdr->sh_offset = offset;
257 dat_shdr->sh_size = dslen;
258 dat_shdr->sh_entsize = 1;
259 dat_shdr->sh_addralign = OUT_ALIGNMENT;
260 offset += dat_shdr->sh_size;
262 datrel_shdr->sh_type = USERELA ? SHT_RELA : SHT_REL;
263 datrel_shdr->sh_offset = offset;
264 datrel_shdr->sh_size = ndsrels * sizeof(dsrels[0]);
265 datrel_shdr->sh_entsize = sizeof(dsrels[0]);
266 datrel_shdr->sh_link = SEC_SYMS;
267 datrel_shdr->sh_info = SEC_DAT;
268 offset += datrel_shdr->sh_size;
270 bss_shdr->sh_type = SHT_NOBITS;
271 bss_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
272 bss_shdr->sh_offset = offset;
273 bss_shdr->sh_size = bss_len();
274 bss_shdr->sh_entsize = 1;
275 bss_shdr->sh_addralign = OUT_ALIGNMENT;
277 symstr_shdr->sh_type = SHT_STRTAB;
278 symstr_shdr->sh_offset = offset;
279 symstr_shdr->sh_size = nsymstr;
280 symstr_shdr->sh_entsize = 1;
281 offset += symstr_shdr->sh_size;
283 write(fd, &ehdr, sizeof(ehdr));
284 write(fd, shdr, NSECS * sizeof(shdr[0]));
285 write(fd, cs, cslen);
286 write(fd, rels, nrels * sizeof(rels[0]));
287 write(fd, syms, nsyms * sizeof(syms[0]));
288 write(fd, ds, dslen);
289 write(fd, dsrels, ndsrels * sizeof(dsrels[0]));
290 write(fd, symstr, nsymstr);
293 /* architecture dependent functions */
295 #ifdef NEATCC_ARM
296 static void ehdr_init(Elf_Ehdr *ehdr)
298 ehdr->e_machine = EM_ARM;
299 ehdr->e_flags = EF_ARM_EABI_VER4;
302 static int rel_type(int flags)
304 if (flags & OUT_RL24)
305 return R_ARM_PC24;
306 return flags & OUT_RLREL ? R_ARM_REL32 : R_ARM_ABS32;
309 #endif
311 #ifdef NEATCC_X64
312 static void ehdr_init(Elf_Ehdr *ehdr)
314 ehdr->e_machine = EM_X86_64;
317 static int rel_type(int flags)
319 if (flags & OUT_RLREL)
320 return R_X86_64_PC32;
321 if (flags & OUT_RL32)
322 return flags & OUT_RLSX ? R_X86_64_32S : R_X86_64_32;
323 return R_X86_64_64;
325 #endif
327 #ifdef NEATCC_X86
328 static void ehdr_init(Elf_Ehdr *ehdr)
330 ehdr->e_machine = EM_386;
333 static int rel_type(int flags)
335 return flags & OUT_RLREL ? R_386_PC32 : R_386_32;
337 #endif