cc: fix ts_pop() when type is NULL
[neatcc.git] / out.c
blobbed80c57fd525b1244f17d92035eb52d97be24bb
1 #include <elf.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include "gen.h"
6 #define MAXSECS (1 << 7)
7 #define MAXSYMS (1 << 10)
8 #define MAXRELA (1 << 10)
9 #define SEC_SYMS 1
10 #define SEC_SYMSTR 2
11 #define SEC_BEG 3
13 static Elf64_Ehdr ehdr;
14 static Elf64_Shdr shdr[MAXSECS];
15 static int nshdr = SEC_BEG;
16 static Elf64_Sym syms[MAXSYMS];
17 static int nsyms;
18 static char symstr[MAXSYMS * 8];
19 static int nsymstr = 1;
21 static struct sec {
22 char buf[SECSIZE];
23 int len;
24 Elf64_Sym *sym;
25 Elf64_Rela rela[MAXRELA];
26 int nrela;
27 Elf64_Shdr *sec_shdr;
28 Elf64_Shdr *rel_shdr;
29 } secs[MAXSECS];
30 static int nsecs;
31 static struct sec *sec;
33 static char *putstr(char *s, char *r)
35 while (*r)
36 *s++ = *r++;
37 *s++ = '\0';
38 return s;
41 static Elf64_Sym *put_sym(char *name)
43 Elf64_Sym *sym = &syms[nsyms++];
44 sym->st_name = nsymstr;
45 nsymstr = putstr(symstr + nsymstr, name) - symstr;
46 sym->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_FUNC);
47 return sym;
50 static int sym_find(char *name)
52 int i;
53 Elf64_Sym *sym;
54 for (i = 0; i < nsyms; i++)
55 if (!strcmp(name, symstr + syms[i].st_name))
56 return i;
57 sym = put_sym(name);
58 sym->st_shndx = SHN_UNDEF;
59 return sym - syms;
62 void out_func_beg(char *name)
64 sec = &secs[nsecs++];
65 sec->sym = put_sym(name);
66 sec->sym->st_shndx = nshdr;
67 sec->sec_shdr = &shdr[nshdr++];
68 sec->rel_shdr = &shdr[nshdr++];
69 sec->rel_shdr->sh_link = SEC_SYMS;
70 sec->rel_shdr->sh_info = sec->sec_shdr - shdr;
73 void out_func_end(char *buf, int len)
75 memcpy(sec->buf, buf, len);
76 sec->len = len;
77 sec->sym->st_size = len;
80 void out_rela(char *name, int off)
82 Elf64_Rela *rela = &sec->rela[sec->nrela++];
83 rela->r_offset = off;
84 rela->r_info = ELF64_R_INFO(sym_find(name), R_X86_64_32);
87 void out_write(int fd)
89 Elf64_Shdr *symstr_shdr = &shdr[SEC_SYMSTR];
90 Elf64_Shdr *syms_shdr = &shdr[SEC_SYMS];
91 unsigned long offset = sizeof(ehdr);
92 int i;
94 ehdr.e_ident[0] = 0x7f;
95 ehdr.e_ident[1] = 'E';
96 ehdr.e_ident[2] = 'L';
97 ehdr.e_ident[3] = 'F';
98 ehdr.e_ident[4] = ELFCLASS64;
99 ehdr.e_ident[5] = ELFDATA2LSB;
100 ehdr.e_ident[6] = EV_CURRENT;
101 ehdr.e_type = ET_REL;
102 ehdr.e_machine = EM_X86_64;
103 ehdr.e_version = EV_CURRENT;
104 ehdr.e_ehsize = sizeof(ehdr);
105 ehdr.e_shentsize = sizeof(shdr[0]);
106 ehdr.e_shoff = offset;
107 ehdr.e_shnum = nshdr;
108 ehdr.e_shstrndx = SEC_SYMSTR;
109 offset += sizeof(shdr[0]) * nshdr;
111 syms_shdr->sh_type = SHT_SYMTAB;
112 syms_shdr->sh_offset = offset;
113 syms_shdr->sh_size = nsyms * sizeof(syms[0]);
114 syms_shdr->sh_entsize = sizeof(syms[0]);
115 syms_shdr->sh_link = SEC_SYMSTR;
116 offset += syms_shdr->sh_size;
118 symstr_shdr->sh_type = SHT_STRTAB;
119 symstr_shdr->sh_offset = offset;
120 symstr_shdr->sh_size = nsymstr;
121 symstr_shdr->sh_entsize = 1;
122 offset += symstr_shdr->sh_size;
124 for (i = 0; i < nsecs; i++) {
125 struct sec *sec = &secs[i];
127 sec->sec_shdr->sh_type = SHT_PROGBITS;
128 sec->sec_shdr->sh_flags = SHF_EXECINSTR;
129 sec->sec_shdr->sh_offset = offset;
130 sec->sec_shdr->sh_size = sec->len;
131 sec->sec_shdr->sh_entsize = 1;
132 offset += sec->sec_shdr->sh_size;
134 sec->rel_shdr->sh_type = SHT_RELA;
135 sec->rel_shdr->sh_offset = offset;
136 sec->rel_shdr->sh_size = sec->nrela * sizeof(sec->rela[0]);
137 sec->rel_shdr->sh_entsize = sizeof(sec->rela[0]);
138 offset += sec->rel_shdr->sh_size;
141 write(fd, &ehdr, sizeof(ehdr));
142 write(fd, shdr, sizeof(shdr[0]) * nshdr);
143 write(fd, syms, sizeof(syms[0]) * nsyms);
144 write(fd, symstr, nsymstr);
145 for (i = 0; i < nsecs; i++) {
146 struct sec *sec = &secs[i];
147 write(fd, sec->buf, sec->len);
148 write(fd, sec->rela, sec->nrela * sizeof(sec->rela[0]));