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