Pull out existing re-layouting code
[centaur.git] / src / model / reladd.c
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <sys/types.h>
5 #include <libelf/gelf.h>
6 #include <libelfu/libelfu.h>
7
8
9 static ElfuScn* insertSection(ElfuElf *me, ElfuElf *mrel, ElfuScn *oldscn)
10 {
11   ElfuScn *newscn = NULL;
12   GElf_Addr injAddr;
13   GElf_Off injOffset;
14   ElfuPhdr *injPhdr;
15
16   if (oldscn->shdr.sh_flags & SHF_ALLOC) {
17     newscn = elfu_mCloneScn(oldscn);
18     if (!newscn) {
19       return NULL;
20     }
21
22
23     injAddr = elfu_mLayoutGetSpaceInPhdr(me,
24                                          newscn->shdr.sh_size,
25                                          newscn->shdr.sh_addralign,
26                                          newscn->shdr.sh_flags & SHF_WRITE,
27                                          newscn->shdr.sh_flags & SHF_EXECINSTR,
28                                          &injPhdr);
29
30     if (!injPhdr) {
31       ELFU_WARN("insertSection: Could not find a place to insert section.\n");
32       goto ERROR;
33     }
34
35     ELFU_INFO("Inserting %s at address 0x%jx...\n",
36               elfu_mScnName(mrel, oldscn),
37               injAddr);
38
39     injOffset = injAddr - injPhdr->phdr.p_vaddr + injPhdr->phdr.p_offset;
40
41     newscn->shdr.sh_addr = injAddr;
42     newscn->shdr.sh_offset = injOffset;
43
44     if (CIRCLEQ_EMPTY(&injPhdr->childScnList)
45         || CIRCLEQ_LAST(&injPhdr->childScnList)->shdr.sh_offset < injOffset) {
46       CIRCLEQ_INSERT_TAIL(&injPhdr->childScnList, newscn, elemChildScn);
47     } else {
48       ElfuScn *ms;
49       CIRCLEQ_FOREACH(ms, &injPhdr->childScnList, elemChildScn) {
50         if (injOffset < ms->shdr.sh_offset) {
51           CIRCLEQ_INSERT_BEFORE(&injPhdr->childScnList, ms, newscn, elemChildScn);
52           break;
53         }
54       }
55     }
56
57     /* Inject name */
58     // TODO
59     newscn->shdr.sh_name = 0;
60
61     // TODO: Relocate
62
63     return newscn;
64   } else {
65       ELFU_WARN("insertSection: Skipping section %s with flags %jd (type %d).\n",
66                 elfu_mScnName(mrel, oldscn),
67                 oldscn->shdr.sh_flags,
68                 oldscn->shdr.sh_type);
69       goto ERROR;
70   }
71
72   ERROR:
73   if (newscn) {
74     // TODO: Destroy newscn
75   }
76   return NULL;
77 }
78
79
80 int subScnAdd1(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
81 {
82   (void)aux2;
83   ElfuElf *me = (ElfuElf*)aux1;
84
85   ElfuScn *newscn;
86
87   switch(ms->shdr.sh_type) {
88     case SHT_PROGBITS: /* 1 */
89       /* Find a place where it belongs and shove it in. */
90       newscn = insertSection(me, mrel, ms);
91       if (!newscn) {
92         ELFU_WARN("mReladd: Could not insert section %s (type %d), skipping.\n",
93                   elfu_mScnName(mrel, ms),
94                   ms->shdr.sh_type);
95       }
96       break;
97   }
98
99   return 0;
100 }
101
102
103 int subScnAdd2(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
104 {
105   (void)aux2;
106   ElfuElf *me = (ElfuElf*)aux1;
107   (void)me;
108
109   switch(ms->shdr.sh_type) {
110     case SHT_NULL: /* 0 */
111     case SHT_PROGBITS: /* 1 */
112       break;
113
114     case SHT_SYMTAB: /* 2 */
115     case SHT_DYNSYM: /* 11 */
116       /* Merge with the existing table. Take care of string tables also. */
117
118     case SHT_STRTAB: /* 3 */
119       /* May have to be merged with the existing string table for
120        * the symbol table. */
121
122     case SHT_RELA: /* 4 */
123     case SHT_REL: /* 9 */
124       /* Possibly append this in memory to the section model
125        * that it describes. */
126
127     case SHT_NOBITS: /* 8 */
128       /* Expand this to SHT_PROGBITS, then insert as such. */
129
130     case SHT_HASH: /* 5 */
131     case SHT_DYNAMIC: /* 6 */
132     case SHT_SHLIB: /* 10 */
133     case SHT_SYMTAB_SHNDX: /* 18 */
134
135     /* Don't care about the next ones yet. I've never seen
136      * them and they can be implemented when necessary. */
137     case SHT_NOTE: /* 7 */
138     case SHT_INIT_ARRAY: /* 14 */
139     case SHT_FINI_ARRAY: /* 15 */
140     case SHT_PREINIT_ARRAY: /* 16 */
141     case SHT_GROUP: /* 17 */
142     case SHT_NUM: /* 19 */
143     default:
144       ELFU_WARN("mReladd: Skipping section %s (type %d).\n",
145                 elfu_mScnName(mrel, ms),
146                 ms->shdr.sh_type);
147   }
148
149   return 0;
150 }
151
152
153 void elfu_mReladd(ElfuElf *me, ElfuElf *mrel)
154 {
155   assert(me);
156   assert(mrel);
157
158   /* For each section in object file, guess how to insert it */
159   elfu_mScnForall(mrel, subScnAdd1, me, NULL);
160
161   /* Do relocations and other stuff */
162   elfu_mScnForall(mrel, subScnAdd2, me, NULL);
163 }