ncc: define __i386__ for x86 builds
[neatcc.git] / out.c
blob75181d8ef315288c2447f1f961e1cf60ea03b844
1 #include <elf.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include "out.h"
6 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
8 #define MAXSYMS (1 << 12)
9 #define MAXRELA (1 << 12)
10 #define SEC_TEXT 1
11 #define SEC_RELA 2
12 #define SEC_SYMS 3
13 #define SEC_SYMSTR 4
14 #define SEC_DAT 5
15 #define SEC_DATRELA 6
16 #define SEC_BSS 7
17 #define NSECS 8
19 static Elf32_Ehdr ehdr;
20 static Elf32_Shdr shdr[NSECS];
21 static Elf32_Sym syms[MAXSYMS];
22 static int nsyms = 1;
23 static char symstr[MAXSYMS * 8];
24 static int nsymstr = 1;
26 static Elf32_Rel datrela[MAXRELA];
27 static int ndatrela;
28 static Elf32_Rel rela[MAXRELA];
29 static int nrela;
31 static char *putstr(char *s, char *r)
33 while (*r)
34 *s++ = *r++;
35 *s++ = '\0';
36 return s;
39 static int sym_find(char *name)
41 int i;
42 for (i = 0; i < nsyms; i++)
43 if (!strcmp(name, symstr + syms[i].st_name))
44 return i;
45 return -1;
48 static Elf32_Sym *put_sym(char *name)
50 int found = sym_find(name);
51 Elf32_Sym *sym = found != -1 ? &syms[found] : &syms[nsyms++];
52 if (found >= 0)
53 return sym;
54 sym->st_name = nsymstr;
55 nsymstr = putstr(symstr + nsymstr, name) - symstr;
56 sym->st_shndx = SHN_UNDEF;
57 sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC);
58 return sym;
61 #define SYMLOCAL(i) (ELF32_ST_BIND(syms[i].st_info) == STB_LOCAL)
63 static void mvrela(int *mv, Elf32_Rel *rela, int nrela)
65 int i;
66 for (i = 0; i < nrela; i++) {
67 int sym = ELF32_R_SYM(rela[i].r_info);
68 int type = ELF32_R_TYPE(rela[i].r_info);
69 rela[i].r_info = ELF32_R_INFO(mv[sym], type);
73 static int syms_sort(void)
75 int mv[MAXSYMS];
76 int i, j;
77 int glob_beg = 1;
78 for (i = 0; i < nsyms; i++)
79 mv[i] = i;
80 i = 1;
81 j = nsyms - 1;
82 while (1) {
83 Elf32_Sym t;
84 while (i < j && SYMLOCAL(i))
85 i++;
86 while (j >= i && !SYMLOCAL(j))
87 j--;
88 if (i >= j)
89 break;
90 t = syms[j];
91 syms[j] = syms[i];
92 syms[i] = t;
93 mv[i] = j;
94 mv[j] = i;
96 glob_beg = j + 1;
97 mvrela(mv, rela, nrela);
98 mvrela(mv, datrela, ndatrela);
99 return glob_beg;
102 void out_init(int flags)
106 void out_sym(char *name, int flags, int off, int len)
108 Elf32_Sym *sym = put_sym(name);
109 int type = (flags & OUT_CS) ? STT_FUNC : STT_OBJECT;
110 int bind = (flags & OUT_GLOB) ? STB_GLOBAL : STB_LOCAL;
111 if (flags & OUT_CS)
112 sym->st_shndx = SEC_TEXT;
113 if (flags & OUT_DS)
114 sym->st_shndx = SEC_DAT;
115 if (flags & OUT_BSS)
116 sym->st_shndx = SEC_BSS;
117 sym->st_info = ELF32_ST_INFO(bind, type);
118 sym->st_value = off;
119 sym->st_size = len;
122 static int rel_type(int flags)
124 #ifdef NEATCC_ARM
125 if (flags & OUT_REL24)
126 return R_ARM_PC24;
127 return flags & OUT_REL ? R_ARM_REL32 : R_ARM_ABS32;
128 #else
129 return flags & OUT_REL ? R_386_PC32 : R_386_32;
130 #endif
133 static void out_csrel(int idx, int off, int flags)
135 Elf32_Rel *r = &rela[nrela++];
136 r->r_offset = off;
137 r->r_info = ELF32_R_INFO(idx, rel_type(flags));
140 static void out_dsrel(int idx, int off, int flags)
142 Elf32_Rel *r = &datrela[ndatrela++];
143 r->r_offset = off;
144 r->r_info = ELF32_R_INFO(idx, rel_type(flags));
147 void out_rel(char *name, int flags, int off)
149 Elf32_Sym *sym = put_sym(name);
150 int idx = sym - syms;
151 if (flags & OUT_DS)
152 out_dsrel(idx, off, flags);
153 else
154 out_csrel(idx, off, flags);
157 static int bss_len(void)
159 int len = 0;
160 int i;
161 for (i = 0; i < nsyms; i++) {
162 int end = syms[i].st_value + syms[i].st_size;
163 if (syms[i].st_shndx == SEC_BSS)
164 if (len < end)
165 len = end;
167 return len;
170 void out_write(int fd, char *cs, int cslen, char *ds, int dslen)
172 Elf32_Shdr *text_shdr = &shdr[SEC_TEXT];
173 Elf32_Shdr *rela_shdr = &shdr[SEC_RELA];
174 Elf32_Shdr *symstr_shdr = &shdr[SEC_SYMSTR];
175 Elf32_Shdr *syms_shdr = &shdr[SEC_SYMS];
176 Elf32_Shdr *dat_shdr = &shdr[SEC_DAT];
177 Elf32_Shdr *datrela_shdr = &shdr[SEC_DATRELA];
178 Elf32_Shdr *bss_shdr = &shdr[SEC_BSS];
179 unsigned long offset = sizeof(ehdr);
181 ehdr.e_ident[0] = 0x7f;
182 ehdr.e_ident[1] = 'E';
183 ehdr.e_ident[2] = 'L';
184 ehdr.e_ident[3] = 'F';
185 ehdr.e_ident[4] = ELFCLASS32;
186 ehdr.e_ident[5] = ELFDATA2LSB;
187 ehdr.e_ident[6] = EV_CURRENT;
188 ehdr.e_type = ET_REL;
189 #ifdef NEATCC_ARM
190 ehdr.e_machine = EM_ARM;
191 ehdr.e_flags = EF_ARM_EABI_VER4;
192 #else
193 ehdr.e_machine = EM_386;
194 #endif
195 ehdr.e_version = EV_CURRENT;
196 ehdr.e_ehsize = sizeof(ehdr);
197 ehdr.e_shentsize = sizeof(shdr[0]);
198 ehdr.e_shoff = offset;
199 ehdr.e_shnum = NSECS;
200 ehdr.e_shstrndx = SEC_SYMSTR;
201 offset += sizeof(shdr[0]) * NSECS;
203 text_shdr->sh_type = SHT_PROGBITS;
204 text_shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
205 text_shdr->sh_offset = offset;
206 text_shdr->sh_size = cslen;
207 text_shdr->sh_entsize = 1;
208 text_shdr->sh_addralign = OUT_ALIGNMENT;
209 offset += text_shdr->sh_size;
211 rela_shdr->sh_type = SHT_REL;
212 rela_shdr->sh_link = SEC_SYMS;
213 rela_shdr->sh_info = SEC_TEXT;
214 rela_shdr->sh_offset = offset;
215 rela_shdr->sh_size = nrela * sizeof(rela[0]);
216 rela_shdr->sh_entsize = sizeof(rela[0]);
217 offset += rela_shdr->sh_size;
219 syms_shdr->sh_type = SHT_SYMTAB;
220 syms_shdr->sh_offset = offset;
221 syms_shdr->sh_size = nsyms * sizeof(syms[0]);
222 syms_shdr->sh_entsize = sizeof(syms[0]);
223 syms_shdr->sh_link = SEC_SYMSTR;
224 syms_shdr->sh_info = syms_sort();
225 offset += syms_shdr->sh_size;
227 dat_shdr->sh_type = SHT_PROGBITS;
228 dat_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
229 dat_shdr->sh_offset = offset;
230 dat_shdr->sh_size = dslen;
231 dat_shdr->sh_entsize = 1;
232 dat_shdr->sh_addralign = OUT_ALIGNMENT;
233 offset += dat_shdr->sh_size;
235 datrela_shdr->sh_type = SHT_REL;
236 datrela_shdr->sh_offset = offset;
237 datrela_shdr->sh_size = ndatrela * sizeof(datrela[0]);
238 datrela_shdr->sh_entsize = sizeof(datrela[0]);
239 datrela_shdr->sh_link = SEC_SYMS;
240 datrela_shdr->sh_info = SEC_DAT;
241 offset += datrela_shdr->sh_size;
243 bss_shdr->sh_type = SHT_NOBITS;
244 bss_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
245 bss_shdr->sh_offset = offset;
246 bss_shdr->sh_size = bss_len();
247 bss_shdr->sh_entsize = 1;
248 bss_shdr->sh_addralign = OUT_ALIGNMENT;
250 symstr_shdr->sh_type = SHT_STRTAB;
251 symstr_shdr->sh_offset = offset;
252 symstr_shdr->sh_size = nsymstr;
253 symstr_shdr->sh_entsize = 1;
254 offset += symstr_shdr->sh_size;
256 write(fd, &ehdr, sizeof(ehdr));
257 write(fd, shdr, NSECS * sizeof(shdr[0]));
258 write(fd, cs, cslen);
259 write(fd, rela, nrela * sizeof(rela[0]));
260 write(fd, syms, nsyms * sizeof(syms[0]));
261 write(fd, ds, dslen);
262 write(fd, datrela, ndatrela * sizeof(datrela[0]));
263 write(fd, symstr, nsymstr);