summaryrefslogtreecommitdiff
path: root/src/model/reladd.c
blob: 2de03dca43965c6b82a1311e26faea7856110eb4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <libelf/gelf.h>
#include <libelfu/libelfu.h>


static ElfuScn* insertSection(ElfuElf *me, ElfuElf *mrel, ElfuScn *oldscn)
{
  ElfuScn *newscn = NULL;
  GElf_Addr injAddr;
  GElf_Off injOffset;
  ElfuPhdr *injPhdr;

  if (oldscn->shdr.sh_flags & SHF_ALLOC) {
    newscn = elfu_mCloneScn(oldscn);
    if (!newscn) {
      return NULL;
    }


    injAddr = elfu_mLayoutGetSpaceInPhdr(me,
                                         newscn->shdr.sh_size,
                                         newscn->shdr.sh_addralign,
                                         newscn->shdr.sh_flags & SHF_WRITE,
                                         newscn->shdr.sh_flags & SHF_EXECINSTR,
                                         &injPhdr);

    if (!injPhdr) {
      ELFU_WARN("insertSection: Could not find a place to insert section.\n");
      goto ERROR;
    }

    ELFU_INFO("Inserting %s at address 0x%jx...\n",
              elfu_mScnName(mrel, oldscn),
              injAddr);

    injOffset = injAddr - injPhdr->phdr.p_vaddr + injPhdr->phdr.p_offset;

    newscn->shdr.sh_addr = injAddr;
    newscn->shdr.sh_offset = injOffset;

    if (CIRCLEQ_EMPTY(&injPhdr->childScnList)
        || CIRCLEQ_LAST(&injPhdr->childScnList)->shdr.sh_offset < injOffset) {
      CIRCLEQ_INSERT_TAIL(&injPhdr->childScnList, newscn, elemChildScn);
    } else {
      ElfuScn *ms;
      CIRCLEQ_FOREACH(ms, &injPhdr->childScnList, elemChildScn) {
        if (injOffset < ms->shdr.sh_offset) {
          CIRCLEQ_INSERT_BEFORE(&injPhdr->childScnList, ms, newscn, elemChildScn);
          break;
        }
      }
    }

    /* Inject name */
    // TODO
    newscn->shdr.sh_name = 0;

    // TODO: Relocate

    return newscn;
  } else {
      ELFU_WARN("insertSection: Skipping section %s with flags %jd (type %d).\n",
                elfu_mScnName(mrel, oldscn),
                oldscn->shdr.sh_flags,
                oldscn->shdr.sh_type);
      goto ERROR;
  }

  ERROR:
  if (newscn) {
    // TODO: Destroy newscn
  }
  return NULL;
}


int subScnAdd1(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
{
  (void)aux2;
  ElfuElf *me = (ElfuElf*)aux1;

  ElfuScn *newscn;

  switch(ms->shdr.sh_type) {
    case SHT_PROGBITS: /* 1 */
      /* Find a place where it belongs and shove it in. */
      newscn = insertSection(me, mrel, ms);
      if (!newscn) {
        ELFU_WARN("mReladd: Could not insert section %s (type %d), skipping.\n",
                  elfu_mScnName(mrel, ms),
                  ms->shdr.sh_type);
      }
      break;
  }

  return 0;
}


int subScnAdd2(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
{
  (void)aux2;
  ElfuElf *me = (ElfuElf*)aux1;
  (void)me;

  switch(ms->shdr.sh_type) {
    case SHT_NULL: /* 0 */
    case SHT_PROGBITS: /* 1 */
      break;

    case SHT_SYMTAB: /* 2 */
    case SHT_DYNSYM: /* 11 */
      /* Merge with the existing table. Take care of string tables also. */

    case SHT_STRTAB: /* 3 */
      /* May have to be merged with the existing string table for
       * the symbol table. */

    case SHT_RELA: /* 4 */
    case SHT_REL: /* 9 */
      /* Possibly append this in memory to the section model
       * that it describes. */

    case SHT_NOBITS: /* 8 */
      /* Expand this to SHT_PROGBITS, then insert as such. */

    case SHT_HASH: /* 5 */
    case SHT_DYNAMIC: /* 6 */
    case SHT_SHLIB: /* 10 */
    case SHT_SYMTAB_SHNDX: /* 18 */

    /* Don't care about the next ones yet. I've never seen
     * them and they can be implemented when necessary. */
    case SHT_NOTE: /* 7 */
    case SHT_INIT_ARRAY: /* 14 */
    case SHT_FINI_ARRAY: /* 15 */
    case SHT_PREINIT_ARRAY: /* 16 */
    case SHT_GROUP: /* 17 */
    case SHT_NUM: /* 19 */
    default:
      ELFU_WARN("mReladd: Skipping section %s (type %d).\n",
                elfu_mScnName(mrel, ms),
                ms->shdr.sh_type);
  }

  return 0;
}


void elfu_mReladd(ElfuElf *me, ElfuElf *mrel)
{
  assert(me);
  assert(mrel);

  /* For each section in object file, guess how to insert it */
  elfu_mScnForall(mrel, subScnAdd1, me, NULL);

  /* Do relocations and other stuff */
  elfu_mScnForall(mrel, subScnAdd2, me, NULL);

  /* Re-layout to accommodate new contents */
  elfu_mLayoutAuto(me);
}