Basic x86-64 support, not very usable in practice
[centaur.git] / src / modelops / toFile.c
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <libelfu/libelfu.h>
5
6
7 static void flattenSymtab(ElfuElf *me)
8 {
9   ElfuSym *sym;
10   size_t numsyms = 0;
11
12   elfu_mLayoutAuto(me);
13
14   /* Update section indexes and count symbols */
15   CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) {
16     if (sym->scnptr) {
17       sym->shndx = elfu_mScnIndex(me, sym->scnptr);
18     }
19
20     numsyms++;
21   }
22
23   /* Copy symbols to elfclass-specific format */
24   if (me->elfclass == ELFCLASS32) {
25     size_t newsize = (numsyms + 1) * sizeof(Elf32_Sym);
26     size_t i;
27
28     if (me->symtab->data.d_buf) {
29       free(me->symtab->data.d_buf);
30     }
31     me->symtab->data.d_buf = malloc(newsize);
32     assert(me->symtab->data.d_buf);
33
34     me->symtab->data.d_size = newsize;
35     me->symtab->shdr.sh_size = newsize;
36     memset(me->symtab->data.d_buf, 0, newsize);
37
38     i = 1;
39     CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) {
40       Elf32_Sym *es = ((Elf32_Sym*)me->symtab->data.d_buf) + i;
41
42       es->st_name = sym->name;
43       es->st_value = sym->value;
44       es->st_size = sym->size;
45       es->st_info = ELF32_ST_INFO(sym->bind, sym->type);
46       es->st_other = sym->other;
47       es->st_shndx = sym->shndx;
48
49       i++;
50     }
51   } else if (me->elfclass == ELFCLASS64) {
52     size_t newsize = (numsyms + 1) * sizeof(Elf64_Sym);
53     size_t i;
54
55     if (me->symtab->data.d_buf) {
56       free(me->symtab->data.d_buf);
57     }
58     me->symtab->data.d_buf = malloc(newsize);
59     assert(me->symtab->data.d_buf);
60
61     me->symtab->data.d_size = newsize;
62     me->symtab->shdr.sh_size = newsize;
63     memset(me->symtab->data.d_buf, 0, newsize);
64
65     i = 1;
66     CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) {
67       Elf64_Sym *es = ((Elf64_Sym*)me->symtab->data.d_buf) + i;
68
69       es->st_name = sym->name;
70       es->st_value = sym->value;
71       es->st_size = sym->size;
72       es->st_info = ELF64_ST_INFO(sym->bind, sym->type);
73       es->st_other = sym->other;
74       es->st_shndx = sym->shndx;
75
76       i++;
77     }
78   } else {
79     // Unknown elfclass
80     assert(0);
81   }
82
83   elfu_mLayoutAuto(me);
84 }
85
86
87 static void modelToPhdrs(ElfuElf *me, Elf *e)
88 {
89   ElfuPhdr *mp;
90   size_t i;
91
92   /* Count PHDRs */
93   i = 0;
94   CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
95     i++;
96   }
97
98   if (!gelf_newphdr(e, i)) {
99     ELFU_WARNELF("gelf_newphdr");
100   }
101
102   /* Copy PHDRs */
103   i = 0;
104   CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
105     if (!gelf_update_phdr (e, i, &mp->phdr)) {
106       ELFU_WARNELF("gelf_update_phdr");
107     }
108
109     i++;
110   }
111 }
112
113
114
115 static void* modelToSection(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
116 {
117   (void) me;
118   (void) aux2;
119   Elf *e = (Elf*)aux1;
120   Elf_Scn *scnOut;
121
122   scnOut = elf_newscn(e);
123   if (!scnOut) {
124     ELFU_WARNELF("elf_newscn");
125     return (void*)-1;
126   }
127
128
129   /* SHDR */
130   if (ms->linkptr) {
131     ms->shdr.sh_link = elfu_mScnIndex(me, ms->linkptr);
132   }
133   if (ms->infoptr) {
134     ms->shdr.sh_info = elfu_mScnIndex(me, ms->infoptr);
135   }
136   if (!gelf_update_shdr(scnOut, &ms->shdr)) {
137     ELFU_WARNELF("gelf_update_shdr");
138   }
139
140
141   /* Data */
142   if (ms->data.d_buf) {
143     Elf_Data *dataOut = elf_newdata(scnOut);
144     if (!dataOut) {
145       ELFU_WARNELF("elf_newdata");
146     }
147
148     dataOut->d_align = ms->data.d_align;
149     dataOut->d_buf  = ms->data.d_buf;
150     dataOut->d_off  = ms->data.d_off;
151     dataOut->d_type = ms->data.d_type;
152     dataOut->d_size = ms->data.d_size;
153     dataOut->d_version = ms->data.d_version;
154   }
155
156   return NULL;
157 }
158
159
160
161
162
163 void elfu_mToElf(ElfuElf *me, Elf *e)
164 {
165   if (me->symtab) {
166     flattenSymtab(me);
167   }
168
169
170   /* We control the ELF file's layout now. */
171   /* tired's libelf also offers ELF_F_LAYOUT_OVERLAP for overlapping sections,
172    * but we don't want that since we filtered it out in the reading stage
173    * already. It would be too mind-blowing to handle the dependencies between
174    * the PHDRs and sections then... */
175   elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT);
176
177
178   /* EHDR */
179   if (!gelf_newehdr(e, me->elfclass)) {
180     ELFU_WARNELF("gelf_newehdr");
181   }
182
183   if (me->shstrtab) {
184     me->ehdr.e_shstrndx = elfu_mScnIndex(me, me->shstrtab);
185   }
186
187   if (!gelf_update_ehdr(e, &me->ehdr)) {
188     ELFU_WARNELF("gelf_update_ehdr");
189   }
190
191
192   /* Sections */
193   elfu_mScnForall(me, modelToSection, e, NULL);
194
195
196   /* PHDRs */
197   modelToPhdrs(me, e);
198
199
200   elf_flagelf(e, ELF_C_SET, ELF_F_DIRTY);
201 }