Merge symbol tables. (Not fully ELF conformant)
[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     // TODO
53     assert(0);
54   } else {
55     // Never reached
56     assert(0);
57   }
58
59   elfu_mLayoutAuto(me);
60 }
61
62
63 static void modelToPhdrs(ElfuElf *me, Elf *e)
64 {
65   ElfuPhdr *mp;
66   size_t i;
67
68   /* Count PHDRs */
69   i = 0;
70   CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
71     i++;
72   }
73
74   if (!gelf_newphdr(e, i)) {
75     ELFU_WARNELF("gelf_newphdr");
76   }
77
78   /* Copy PHDRs */
79   i = 0;
80   CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
81     if (!gelf_update_phdr (e, i, &mp->phdr)) {
82       ELFU_WARNELF("gelf_update_phdr");
83     }
84
85     i++;
86   }
87 }
88
89
90
91 static void* modelToSection(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
92 {
93   (void) me;
94   (void) aux2;
95   Elf *e = (Elf*)aux1;
96   Elf_Scn *scnOut;
97
98   scnOut = elf_newscn(e);
99   if (!scnOut) {
100     ELFU_WARNELF("elf_newscn");
101     return (void*)-1;
102   }
103
104
105   /* SHDR */
106   if (ms->linkptr) {
107     ms->shdr.sh_link = elfu_mScnIndex(me, ms->linkptr);
108   }
109   if (ms->infoptr) {
110     ms->shdr.sh_info = elfu_mScnIndex(me, ms->infoptr);
111   }
112   if (!gelf_update_shdr(scnOut, &ms->shdr)) {
113     ELFU_WARNELF("gelf_update_shdr");
114   }
115
116
117   /* Data */
118   if (ms->data.d_buf) {
119     Elf_Data *dataOut = elf_newdata(scnOut);
120     if (!dataOut) {
121       ELFU_WARNELF("elf_newdata");
122     }
123
124     dataOut->d_align = ms->data.d_align;
125     dataOut->d_buf  = ms->data.d_buf;
126     dataOut->d_off  = ms->data.d_off;
127     dataOut->d_type = ms->data.d_type;
128     dataOut->d_size = ms->data.d_size;
129     dataOut->d_version = ms->data.d_version;
130   }
131
132   return NULL;
133 }
134
135
136
137
138
139 void elfu_mToElf(ElfuElf *me, Elf *e)
140 {
141   if (me->symtab) {
142     flattenSymtab(me);
143   }
144
145
146   /* We control the ELF file's layout now. */
147   /* tired's libelf also offers ELF_F_LAYOUT_OVERLAP for overlapping sections,
148    * but we don't want that since we filtered it out in the reading stage
149    * already. It would be too mind-blowing to handle the dependencies between
150    * the PHDRs and sections then... */
151   elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT);
152
153
154   /* EHDR */
155   if (!gelf_newehdr(e, me->elfclass)) {
156     ELFU_WARNELF("gelf_newehdr");
157   }
158
159   if (me->shstrtab) {
160     me->ehdr.e_shstrndx = elfu_mScnIndex(me, me->shstrtab);
161   }
162
163   if (!gelf_update_ehdr(e, &me->ehdr)) {
164     ELFU_WARNELF("gelf_update_ehdr");
165   }
166
167
168   /* Sections */
169   elfu_mScnForall(me, modelToSection, e, NULL);
170
171
172   /* PHDRs */
173   modelToPhdrs(me, e);
174
175
176   elf_flagelf(e, ELF_C_SET, ELF_F_DIRTY);
177 }