clean up the interface between ncc.c, gen.c and out.c
[neatcc.git] / out.c
blob2f8451d8aa14e41b3f6d9e744f6e0be2a90819bd
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 return flags & OUT_REL ? R_386_PC32 : R_386_32;
127 static void out_csrel(int idx, int off, int flags)
129 Elf32_Rel *r = &rela[nrela++];
130 r->r_offset = off;
131 r->r_info = ELF32_R_INFO(idx, rel_type(flags));
134 static void out_dsrel(int idx, int off, int flags)
136 Elf32_Rel *r = &datrela[ndatrela++];
137 r->r_offset = off;
138 r->r_info = ELF32_R_INFO(idx, rel_type(flags));
141 void out_rel(char *name, int flags, int off)
143 Elf32_Sym *sym = put_sym(name);
144 int idx = sym - syms;
145 if (flags & OUT_DS)
146 out_dsrel(idx, off, flags);
147 else
148 out_csrel(idx, off, flags);
151 static int bss_len(void)
153 int len = 0;
154 int i;
155 for (i = 0; i < nsyms; i++) {
156 int end = syms[i].st_value + syms[i].st_size;
157 if (syms[i].st_shndx == SEC_BSS)
158 if (len < end)
159 len = end;
161 return len;
164 void out_write(int fd, char *cs, int cslen, char *ds, int dslen)
166 Elf32_Shdr *text_shdr = &shdr[SEC_TEXT];
167 Elf32_Shdr *rela_shdr = &shdr[SEC_RELA];
168 Elf32_Shdr *symstr_shdr = &shdr[SEC_SYMSTR];
169 Elf32_Shdr *syms_shdr = &shdr[SEC_SYMS];
170 Elf32_Shdr *dat_shdr = &shdr[SEC_DAT];
171 Elf32_Shdr *datrela_shdr = &shdr[SEC_DATRELA];
172 Elf32_Shdr *bss_shdr = &shdr[SEC_BSS];
173 unsigned long offset = sizeof(ehdr);
175 ehdr.e_ident[0] = 0x7f;
176 ehdr.e_ident[1] = 'E';
177 ehdr.e_ident[2] = 'L';
178 ehdr.e_ident[3] = 'F';
179 ehdr.e_ident[4] = ELFCLASS32;
180 ehdr.e_ident[5] = ELFDATA2LSB;
181 ehdr.e_ident[6] = EV_CURRENT;
182 ehdr.e_type = ET_REL;
183 ehdr.e_machine = EM_386;
184 ehdr.e_version = EV_CURRENT;
185 ehdr.e_ehsize = sizeof(ehdr);
186 ehdr.e_shentsize = sizeof(shdr[0]);
187 ehdr.e_shoff = offset;
188 ehdr.e_shnum = NSECS;
189 ehdr.e_shstrndx = SEC_SYMSTR;
190 offset += sizeof(shdr[0]) * NSECS;
192 text_shdr->sh_type = SHT_PROGBITS;
193 text_shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
194 text_shdr->sh_offset = offset;
195 text_shdr->sh_size = cslen;
196 text_shdr->sh_entsize = 1;
197 offset += text_shdr->sh_size;
199 rela_shdr->sh_type = SHT_REL;
200 rela_shdr->sh_link = SEC_SYMS;
201 rela_shdr->sh_info = SEC_TEXT;
202 rela_shdr->sh_offset = offset;
203 rela_shdr->sh_size = nrela * sizeof(rela[0]);
204 rela_shdr->sh_entsize = sizeof(rela[0]);
205 offset += rela_shdr->sh_size;
207 syms_shdr->sh_type = SHT_SYMTAB;
208 syms_shdr->sh_offset = offset;
209 syms_shdr->sh_size = nsyms * sizeof(syms[0]);
210 syms_shdr->sh_entsize = sizeof(syms[0]);
211 syms_shdr->sh_link = SEC_SYMSTR;
212 syms_shdr->sh_info = syms_sort();
213 offset += syms_shdr->sh_size;
215 dat_shdr->sh_type = SHT_PROGBITS;
216 dat_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
217 dat_shdr->sh_offset = offset;
218 dat_shdr->sh_size = dslen;
219 dat_shdr->sh_entsize = 1;
220 dat_shdr->sh_addralign = 4;
221 offset += dat_shdr->sh_size;
223 datrela_shdr->sh_type = SHT_REL;
224 datrela_shdr->sh_offset = offset;
225 datrela_shdr->sh_size = ndatrela * sizeof(datrela[0]);
226 datrela_shdr->sh_entsize = sizeof(datrela[0]);
227 datrela_shdr->sh_link = SEC_SYMS;
228 datrela_shdr->sh_info = SEC_DAT;
229 offset += datrela_shdr->sh_size;
231 bss_shdr->sh_type = SHT_NOBITS;
232 bss_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
233 bss_shdr->sh_offset = offset;
234 bss_shdr->sh_size = bss_len();
235 bss_shdr->sh_entsize = 1;
236 bss_shdr->sh_addralign = 4;
238 symstr_shdr->sh_type = SHT_STRTAB;
239 symstr_shdr->sh_offset = offset;
240 symstr_shdr->sh_size = nsymstr;
241 symstr_shdr->sh_entsize = 1;
242 offset += symstr_shdr->sh_size;
244 write(fd, &ehdr, sizeof(ehdr));
245 write(fd, shdr, NSECS * sizeof(shdr[0]));
246 write(fd, cs, cslen);
247 write(fd, rela, nrela * sizeof(rela[0]));
248 write(fd, syms, nsyms * sizeof(syms[0]));
249 write(fd, ds, dslen);
250 write(fd, datrela, ndatrela * sizeof(datrela[0]));
251 write(fd, symstr, nsymstr);