gen: don't let o_cast() change dereferenced type
[neatcc.git] / out.c
blob63f63d9e33dfa693c74be9f5c2afec5f111ff34c
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 if (flags & OUT_REL24)
125 return R_ARM_PC24;
126 if (flags & OUT_REL)
127 return R_ARM_REL32;
128 return R_ARM_ABS32;
131 static void out_csrel(int idx, int off, int flags)
133 Elf32_Rel *r = &rela[nrela++];
134 r->r_offset = off;
135 r->r_info = ELF32_R_INFO(idx, rel_type(flags));
138 static void out_dsrel(int idx, int off, int flags)
140 Elf32_Rel *r = &datrela[ndatrela++];
141 r->r_offset = off;
142 r->r_info = ELF32_R_INFO(idx, rel_type(flags));
145 void out_rel(char *name, int flags, int off)
147 Elf32_Sym *sym = put_sym(name);
148 int idx = sym - syms;
149 if (flags & OUT_DS)
150 out_dsrel(idx, off, flags);
151 else
152 out_csrel(idx, off, flags);
155 static int bss_len(void)
157 int len = 0;
158 int i;
159 for (i = 0; i < nsyms; i++) {
160 int end = syms[i].st_value + syms[i].st_size;
161 if (syms[i].st_shndx == SEC_BSS)
162 if (len < end)
163 len = end;
165 return len;
168 void out_write(int fd, char *cs, int cslen, char *ds, int dslen)
170 Elf32_Shdr *text_shdr = &shdr[SEC_TEXT];
171 Elf32_Shdr *rela_shdr = &shdr[SEC_RELA];
172 Elf32_Shdr *symstr_shdr = &shdr[SEC_SYMSTR];
173 Elf32_Shdr *syms_shdr = &shdr[SEC_SYMS];
174 Elf32_Shdr *dat_shdr = &shdr[SEC_DAT];
175 Elf32_Shdr *datrela_shdr = &shdr[SEC_DATRELA];
176 Elf32_Shdr *bss_shdr = &shdr[SEC_BSS];
177 unsigned long offset = sizeof(ehdr);
179 ehdr.e_ident[0] = 0x7f;
180 ehdr.e_ident[1] = 'E';
181 ehdr.e_ident[2] = 'L';
182 ehdr.e_ident[3] = 'F';
183 ehdr.e_ident[4] = ELFCLASS32;
184 ehdr.e_ident[5] = ELFDATA2LSB;
185 ehdr.e_ident[6] = EV_CURRENT;
186 ehdr.e_type = ET_REL;
187 ehdr.e_machine = EM_ARM;
188 ehdr.e_flags = EF_ARM_EABI_VER4;
189 ehdr.e_version = EV_CURRENT;
190 ehdr.e_ehsize = sizeof(ehdr);
191 ehdr.e_shentsize = sizeof(shdr[0]);
192 ehdr.e_shoff = offset;
193 ehdr.e_shnum = NSECS;
194 ehdr.e_shstrndx = SEC_SYMSTR;
195 offset += sizeof(shdr[0]) * NSECS;
197 text_shdr->sh_type = SHT_PROGBITS;
198 text_shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
199 text_shdr->sh_offset = offset;
200 text_shdr->sh_size = cslen;
201 text_shdr->sh_entsize = 1;
202 offset += text_shdr->sh_size;
204 rela_shdr->sh_type = SHT_REL;
205 rela_shdr->sh_link = SEC_SYMS;
206 rela_shdr->sh_info = SEC_TEXT;
207 rela_shdr->sh_offset = offset;
208 rela_shdr->sh_size = nrela * sizeof(rela[0]);
209 rela_shdr->sh_entsize = sizeof(rela[0]);
210 offset += rela_shdr->sh_size;
212 syms_shdr->sh_type = SHT_SYMTAB;
213 syms_shdr->sh_offset = offset;
214 syms_shdr->sh_size = nsyms * sizeof(syms[0]);
215 syms_shdr->sh_entsize = sizeof(syms[0]);
216 syms_shdr->sh_link = SEC_SYMSTR;
217 syms_shdr->sh_info = syms_sort();
218 offset += syms_shdr->sh_size;
220 dat_shdr->sh_type = SHT_PROGBITS;
221 dat_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
222 dat_shdr->sh_offset = offset;
223 dat_shdr->sh_size = dslen;
224 dat_shdr->sh_entsize = 1;
225 dat_shdr->sh_addralign = 4;
226 offset += dat_shdr->sh_size;
228 datrela_shdr->sh_type = SHT_REL;
229 datrela_shdr->sh_offset = offset;
230 datrela_shdr->sh_size = ndatrela * sizeof(datrela[0]);
231 datrela_shdr->sh_entsize = sizeof(datrela[0]);
232 datrela_shdr->sh_link = SEC_SYMS;
233 datrela_shdr->sh_info = SEC_DAT;
234 offset += datrela_shdr->sh_size;
236 bss_shdr->sh_type = SHT_NOBITS;
237 bss_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
238 bss_shdr->sh_offset = offset;
239 bss_shdr->sh_size = bss_len();
240 bss_shdr->sh_entsize = 1;
241 bss_shdr->sh_addralign = 4;
243 symstr_shdr->sh_type = SHT_STRTAB;
244 symstr_shdr->sh_offset = offset;
245 symstr_shdr->sh_size = nsymstr;
246 symstr_shdr->sh_entsize = 1;
247 offset += symstr_shdr->sh_size;
249 write(fd, &ehdr, sizeof(ehdr));
250 write(fd, shdr, NSECS * sizeof(shdr[0]));
251 write(fd, cs, cslen);
252 write(fd, rela, nrela * sizeof(rela[0]));
253 write(fd, syms, nsyms * sizeof(syms[0]));
254 write(fd, ds, dslen);
255 write(fd, datrela, ndatrela * sizeof(datrela[0]));
256 write(fd, symstr, nsymstr);