cpp: define __i386__; __x86_64__ is no longer supported
[neatcc.git] / out.c
blob15658e4074acc536b11313040879ce49021c4885
1 #include <elf.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include "gen.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;
25 static int bsslen;
26 static char dat[SECSIZE];
27 static int datlen;
28 static Elf32_Rel datrela[MAXRELA];
29 static int ndatrela;
31 static char buf[SECSIZE];
32 static int len;
33 static Elf32_Sym *cur_sym;
34 static Elf32_Rel rela[MAXRELA];
35 static int nrela;
37 static char *putstr(char *s, char *r)
39 while (*r)
40 *s++ = *r++;
41 *s++ = '\0';
42 return s;
45 static int sym_find(char *name)
47 int i;
48 for (i = 0; i < nsyms; i++)
49 if (!strcmp(name, symstr + syms[i].st_name))
50 return i;
51 return -1;
54 static Elf32_Sym *put_sym(char *name)
56 int found = name ? sym_find(name) : -1;
57 Elf32_Sym *sym = found != -1 ? &syms[found] : &syms[nsyms++];
58 if (!name)
59 sym->st_name = 0;
60 if (name && found == -1) {
61 sym->st_name = nsymstr;
62 nsymstr = putstr(symstr + nsymstr, name) - symstr;
64 return sym;
67 #define S_BIND(global) ((global) ? STB_GLOBAL : STB_LOCAL)
69 long out_func_beg(char *name, int global)
71 cur_sym = put_sym(name);
72 cur_sym->st_shndx = SEC_TEXT;
73 cur_sym->st_info = ELF32_ST_INFO(S_BIND(global), STT_FUNC);
74 cur_sym->st_value = len;
75 return cur_sym - syms;
78 void out_func_end(char *sec, int sec_len)
80 memcpy(buf + len, sec, sec_len);
81 len += sec_len;
82 cur_sym->st_size = sec_len;
85 void out_rela(long addr, int off, int rel)
87 Elf32_Rel *r = &rela[nrela++];
88 r->r_offset = cur_sym->st_value + off;
89 r->r_info = ELF32_R_INFO(addr, rel ? R_386_PC32 : R_386_32);
92 void out_datrela(long addr, long dataddr, int off)
94 Elf32_Rel *r = &datrela[ndatrela++];
95 r->r_offset = syms[dataddr].st_value + off;
96 r->r_info = ELF32_R_INFO(addr, R_386_32);
99 #define SYMLOCAL(i) (ELF32_ST_BIND(syms[i].st_info) == STB_LOCAL)
101 static void mvrela(int *mv, Elf32_Rel *rela, int nrela)
103 int i;
104 for (i = 0; i < nrela; i++) {
105 int sym = ELF32_R_SYM(rela[i].r_info);
106 int type = ELF32_R_TYPE(rela[i].r_info);
107 rela[i].r_info = ELF32_R_INFO(mv[sym], type);
111 static int syms_sort(void)
113 int mv[MAXSYMS];
114 int i, j;
115 int glob_beg = 1;
116 for (i = 0; i < nsyms; i++)
117 mv[i] = i;
118 i = 1;
119 j = nsyms - 1;
120 while (1) {
121 Elf32_Sym t;
122 while (i < j && SYMLOCAL(i))
123 i++;
124 while (j >= i && !SYMLOCAL(j))
125 j--;
126 if (i >= j)
127 break;
128 t = syms[j];
129 syms[j] = syms[i];
130 syms[i] = t;
131 mv[i] = j;
132 mv[j] = i;
134 glob_beg = j + 1;
135 mvrela(mv, rela, nrela);
136 mvrela(mv, datrela, ndatrela);
137 return glob_beg;
140 void out_write(int fd)
142 Elf32_Shdr *text_shdr = &shdr[SEC_TEXT];
143 Elf32_Shdr *rela_shdr = &shdr[SEC_RELA];
144 Elf32_Shdr *symstr_shdr = &shdr[SEC_SYMSTR];
145 Elf32_Shdr *syms_shdr = &shdr[SEC_SYMS];
146 Elf32_Shdr *dat_shdr = &shdr[SEC_DAT];
147 Elf32_Shdr *datrela_shdr = &shdr[SEC_DATRELA];
148 Elf32_Shdr *bss_shdr = &shdr[SEC_BSS];
149 unsigned long offset = sizeof(ehdr);
151 ehdr.e_ident[0] = 0x7f;
152 ehdr.e_ident[1] = 'E';
153 ehdr.e_ident[2] = 'L';
154 ehdr.e_ident[3] = 'F';
155 ehdr.e_ident[4] = ELFCLASS32;
156 ehdr.e_ident[5] = ELFDATA2LSB;
157 ehdr.e_ident[6] = EV_CURRENT;
158 ehdr.e_type = ET_REL;
159 ehdr.e_machine = EM_386;
160 ehdr.e_version = EV_CURRENT;
161 ehdr.e_ehsize = sizeof(ehdr);
162 ehdr.e_shentsize = sizeof(shdr[0]);
163 ehdr.e_shoff = offset;
164 ehdr.e_shnum = NSECS;
165 ehdr.e_shstrndx = SEC_SYMSTR;
166 offset += sizeof(shdr[0]) * NSECS;
168 text_shdr->sh_type = SHT_PROGBITS;
169 text_shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
170 text_shdr->sh_offset = offset;
171 text_shdr->sh_size = len;
172 text_shdr->sh_entsize = 1;
173 offset += text_shdr->sh_size;
175 rela_shdr->sh_type = SHT_REL;
176 rela_shdr->sh_link = SEC_SYMS;
177 rela_shdr->sh_info = SEC_TEXT;
178 rela_shdr->sh_offset = offset;
179 rela_shdr->sh_size = nrela * sizeof(rela[0]);
180 rela_shdr->sh_entsize = sizeof(rela[0]);
181 offset += rela_shdr->sh_size;
183 syms_shdr->sh_type = SHT_SYMTAB;
184 syms_shdr->sh_offset = offset;
185 syms_shdr->sh_size = nsyms * sizeof(syms[0]);
186 syms_shdr->sh_entsize = sizeof(syms[0]);
187 syms_shdr->sh_link = SEC_SYMSTR;
188 syms_shdr->sh_info = syms_sort();
189 offset += syms_shdr->sh_size;
191 dat_shdr->sh_type = SHT_PROGBITS;
192 dat_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
193 dat_shdr->sh_offset = offset;
194 dat_shdr->sh_size = datlen;
195 dat_shdr->sh_entsize = 1;
196 dat_shdr->sh_addralign = 4;
197 offset += dat_shdr->sh_size;
199 datrela_shdr->sh_type = SHT_REL;
200 datrela_shdr->sh_offset = offset;
201 datrela_shdr->sh_size = ndatrela * sizeof(datrela[0]);
202 datrela_shdr->sh_entsize = sizeof(datrela[0]);
203 datrela_shdr->sh_link = SEC_SYMS;
204 datrela_shdr->sh_info = SEC_DAT;
205 offset += datrela_shdr->sh_size;
207 bss_shdr->sh_type = SHT_NOBITS;
208 bss_shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
209 bss_shdr->sh_offset = offset;
210 bss_shdr->sh_size = bsslen;
211 bss_shdr->sh_entsize = 1;
212 bss_shdr->sh_addralign = 4;
214 symstr_shdr->sh_type = SHT_STRTAB;
215 symstr_shdr->sh_offset = offset;
216 symstr_shdr->sh_size = nsymstr;
217 symstr_shdr->sh_entsize = 1;
218 offset += symstr_shdr->sh_size;
220 write(fd, &ehdr, sizeof(ehdr));
221 write(fd, shdr, NSECS * sizeof(shdr[0]));
222 write(fd, buf, len);
223 write(fd, rela, nrela * sizeof(rela[0]));
224 write(fd, syms, nsyms * sizeof(syms[0]));
225 write(fd, dat, datlen);
226 write(fd, datrela, ndatrela * sizeof(datrela[0]));
227 write(fd, symstr, nsymstr);
230 long out_mkvar(char *name, int size, int global)
232 Elf32_Sym *sym = put_sym(name);
233 sym->st_shndx = SEC_BSS;
234 sym->st_value = bsslen;
235 sym->st_size = size;
236 sym->st_info = ELF32_ST_INFO(S_BIND(global), STT_OBJECT);
237 bsslen = ALIGN(bsslen + size, 4);
238 return sym - syms;
241 long out_mkundef(char *name, int sz)
243 Elf32_Sym *sym = put_sym(name);
244 sym->st_shndx = SHN_UNDEF;
245 sym->st_info = ELF32_ST_INFO(STB_GLOBAL, sz ? STT_OBJECT : STT_FUNC);
246 sym->st_size = sz;
247 return sym - syms;
250 long out_mkdat(char *name, char *buf, int len, int global)
252 Elf32_Sym *sym = put_sym(name);
253 sym->st_shndx = SEC_DAT;
254 sym->st_value = datlen;
255 sym->st_size = len;
256 sym->st_info = ELF32_ST_INFO(S_BIND(global), STT_OBJECT);
257 if (buf)
258 memcpy(dat + datlen, buf, len);
259 else
260 memset(dat + datlen, 0, len);
261 datlen = ALIGN(datlen + len, 4);
262 return sym - syms;
265 void out_datcpy(long addr, int off, char *buf, int len)
267 memcpy(dat + syms[addr].st_value + off, buf, len);