Subversion Repositories Kolibri OS

Rev

Rev 4349 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4349 Rev 4866
1
/* pseudo-reloc.c
1
/* pseudo-reloc.c
2
 
2
 
3
   Contributed by Egor Duda  
3
   Contributed by Egor Duda  
4
   Modified by addition of runtime_pseudo_reloc version 2
4
   Modified by addition of runtime_pseudo_reloc version 2
5
   by Kai Tietz  
5
   by Kai Tietz  
6
 
6
 
7
   THIS SOFTWARE IS NOT COPYRIGHTED
7
   THIS SOFTWARE IS NOT COPYRIGHTED
8
 
8
 
9
   This source code is offered for use in the public domain. You may
9
   This source code is offered for use in the public domain. You may
10
   use, modify or distribute it freely.
10
   use, modify or distribute it freely.
11
 
11
 
12
   This code is distributed in the hope that it will be useful but
12
   This code is distributed in the hope that it will be useful but
13
   WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY
13
   WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY
14
   DISCLAMED. This includes but is not limited to warrenties of
14
   DISCLAMED. This includes but is not limited to warrenties of
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
*/
16
*/
17
 
17
 
18
#include 
18
#include 
19
#include 
19
#include 
20
#include 
20
#include 
21
#include 
21
#include 
22
#include 
-
 
23
 
22
 
24
extern char __RUNTIME_PSEUDO_RELOC_LIST__;
23
extern char __RUNTIME_PSEUDO_RELOC_LIST__;
25
extern char __RUNTIME_PSEUDO_RELOC_LIST_END__;
24
extern char __RUNTIME_PSEUDO_RELOC_LIST_END__;
26
extern char _image_base__;
25
extern char _image_base__;
27
 
26
 
28
void _pei386_runtime_relocator (void);
27
void _pei386_runtime_relocator (void);
29
 
28
 
30
/* v1 relocation is basically:
29
/* v1 relocation is basically:
31
 *   *(base + .target) += .addend
30
 *   *(base + .target) += .addend
32
 * where (base + .target) is always assumed to point
31
 * where (base + .target) is always assumed to point
33
 * to a DWORD (4 bytes).
32
 * to a DWORD (4 bytes).
34
 */
33
 */
35
typedef struct {
34
typedef struct {
36
  uint32_t addend;
35
  uint32_t addend;
37
  uint32_t target;
36
  uint32_t target;
38
} runtime_pseudo_reloc_item_v1;
37
} runtime_pseudo_reloc_item_v1;
39
 
38
 
40
/* v2 relocation is more complex. In effect, it is
39
/* v2 relocation is more complex. In effect, it is
41
 *    *(base + .target) += *(base + .sym) - (base + .sym)
40
 *    *(base + .target) += *(base + .sym) - (base + .sym)
42
 * with care taken in both reading, sign extension, and writing
41
 * with care taken in both reading, sign extension, and writing
43
 * because .flags may indicate that (base + .target) may point
42
 * because .flags may indicate that (base + .target) may point
44
 * to a BYTE, WORD, DWORD, or QWORD (w64).
43
 * to a BYTE, WORD, DWORD, or QWORD (w64).
45
 */
44
 */
46
typedef struct {
45
typedef struct {
47
  uint32_t sym;
46
  uint32_t sym;
48
  uint32_t target;
47
  uint32_t target;
49
  uint32_t flags;
48
  uint32_t flags;
50
} runtime_pseudo_reloc_item_v2;
49
} runtime_pseudo_reloc_item_v2;
51
 
50
 
52
typedef struct {
51
typedef struct {
53
  uint32_t magic1;
52
  uint32_t magic1;
54
  uint32_t magic2;
53
  uint32_t magic2;
55
  uint32_t version;
54
  uint32_t version;
56
} runtime_pseudo_reloc_v2;
55
} runtime_pseudo_reloc_v2;
57
 
56
 
58
#define RP_VERSION_V1 0
57
#define RP_VERSION_V1 0
59
#define RP_VERSION_V2 1
58
#define RP_VERSION_V2 1
60
 
59
 
61
static void
60
static void
62
do_pseudo_reloc (void * start, void * end, void * base)
61
do_pseudo_reloc (void * start, void * end, void * base)
63
{
62
{
64
  ptrdiff_t addr_imp, reldata;
63
  ptrdiff_t addr_imp, reldata;
65
  ptrdiff_t reloc_target = (ptrdiff_t) ((char *)end - (char*)start);
64
  ptrdiff_t reloc_target = (ptrdiff_t) ((char *)end - (char*)start);
66
  runtime_pseudo_reloc_v2 *v2_hdr = (runtime_pseudo_reloc_v2 *) start;
65
  runtime_pseudo_reloc_v2 *v2_hdr = (runtime_pseudo_reloc_v2 *) start;
67
  runtime_pseudo_reloc_item_v2 *r;
66
  runtime_pseudo_reloc_item_v2 *r;
68
 
67
 
69
  /* A valid relocation list will contain at least one entry, and
68
  /* A valid relocation list will contain at least one entry, and
70
   * one v1 data structure (the smallest one) requires two DWORDs.
69
   * one v1 data structure (the smallest one) requires two DWORDs.
71
   * So, if the relocation list is smaller than 8 bytes, bail.
70
   * So, if the relocation list is smaller than 8 bytes, bail.
72
   */
71
   */
73
  if (reloc_target < 8)
72
  if (reloc_target < 8)
74
    return;
73
    return;
75
 
74
 
76
  /* Check if this is the old pseudo relocation version.  */
75
  /* Check if this is the old pseudo relocation version.  */
77
  /* There are two kinds of v1 relocation lists:
76
  /* There are two kinds of v1 relocation lists:
78
   *   1) With a (v2-style) version header. In this case, the
77
   *   1) With a (v2-style) version header. In this case, the
79
   *      first entry in the list is a 3-DWORD structure, with
78
   *      first entry in the list is a 3-DWORD structure, with
80
   *      value:
79
   *      value:
81
   *         { 0, 0, RP_VERSION_V1 }
80
   *         { 0, 0, RP_VERSION_V1 }
82
   *      In this case, we skip to the next entry in the list,
81
   *      In this case, we skip to the next entry in the list,
83
   *      knowing that all elements after the head item can
82
   *      knowing that all elements after the head item can
84
   *      be cast to runtime_pseudo_reloc_item_v1.
83
   *      be cast to runtime_pseudo_reloc_item_v1.
85
   *   2) Without a (v2-style) version header. In this case, the
84
   *   2) Without a (v2-style) version header. In this case, the
86
   *      first element in the list IS an actual v1 relocation
85
   *      first element in the list IS an actual v1 relocation
87
   *      record, which is two DWORDs.  Because there will never
86
   *      record, which is two DWORDs.  Because there will never
88
   *      be a case where a v1 relocation record has both
87
   *      be a case where a v1 relocation record has both
89
   *      addend == 0 and target == 0, this case will not be
88
   *      addend == 0 and target == 0, this case will not be
90
   *      confused with the prior one.
89
   *      confused with the prior one.
91
   * All current binutils, when generating a v1 relocation list,
90
   * All current binutils, when generating a v1 relocation list,
92
   * use the second (e.g. original) form -- that is, without the
91
   * use the second (e.g. original) form -- that is, without the
93
   * v2-style version header.
92
   * v2-style version header.
94
   */
93
   */
95
  if (reloc_target >= 12
94
  if (reloc_target >= 12
96
      && v2_hdr->magic1 == 0 && v2_hdr->magic2 == 0
95
      && v2_hdr->magic1 == 0 && v2_hdr->magic2 == 0
97
      && v2_hdr->version == RP_VERSION_V1)
96
      && v2_hdr->version == RP_VERSION_V1)
98
    {
97
    {
99
      /* We have a list header item indicating that the rest
98
      /* We have a list header item indicating that the rest
100
       * of the list contains v1 entries.  Move the pointer to
99
       * of the list contains v1 entries.  Move the pointer to
101
       * the first true v1 relocation record.  By definition,
100
       * the first true v1 relocation record.  By definition,
102
       * that v1 element will not have both addend == 0 and
101
       * that v1 element will not have both addend == 0 and
103
       * target == 0 (and thus, when interpreted as a
102
       * target == 0 (and thus, when interpreted as a
104
       * runtime_pseudo_reloc_v2, it will not have both
103
       * runtime_pseudo_reloc_v2, it will not have both
105
       * magic1 == 0 and magic2 == 0).
104
       * magic1 == 0 and magic2 == 0).
106
       */
105
       */
107
      v2_hdr++;
106
      v2_hdr++;
108
    }
107
    }
109
 
108
 
110
  if (v2_hdr->magic1 != 0 || v2_hdr->magic2 != 0)
109
  if (v2_hdr->magic1 != 0 || v2_hdr->magic2 != 0)
111
    {
110
    {
112
      /*************************
111
      /*************************
113
       * Handle v1 relocations *
112
       * Handle v1 relocations *
114
       *************************/
113
       *************************/
115
      runtime_pseudo_reloc_item_v1 * o;
114
      runtime_pseudo_reloc_item_v1 * o;
116
      for (o = (runtime_pseudo_reloc_item_v1 *) v2_hdr;
115
      for (o = (runtime_pseudo_reloc_item_v1 *) v2_hdr;
117
	   o < (runtime_pseudo_reloc_item_v1 *)end;
116
	   o < (runtime_pseudo_reloc_item_v1 *)end;
118
           o++)
117
           o++)
119
	{
118
	{
120
      uint32_t newval;
119
      uint32_t newval;
121
	  reloc_target = (ptrdiff_t) base + o->target;
120
	  reloc_target = (ptrdiff_t) base + o->target;
122
      newval = (*((uint32_t*) reloc_target)) + o->addend;
121
      newval = (*((uint32_t*) reloc_target)) + o->addend;
123
      *(uint32_t*)reloc_target = newval;
122
      *(uint32_t*)reloc_target = newval;
124
	}
123
	}
125
      return;
124
      return;
126
    }
125
    }
127
 
126
 
128
  /* If we got this far, then we have relocations of version 2 or newer */
127
  /* If we got this far, then we have relocations of version 2 or newer */
129
 
128
 
130
  /* Check if this is a known version.  */
129
  /* Check if this is a known version.  */
131
  if (v2_hdr->version != RP_VERSION_V2)
130
  if (v2_hdr->version != RP_VERSION_V2)
132
    {
131
    {
133
//      printf("  Unknown pseudo relocation protocol version %d.\n",
132
//      printf("  Unknown pseudo relocation protocol version %d.\n",
134
//             (int) v2_hdr->version);
133
//             (int) v2_hdr->version);
135
      return;
134
      return;
136
    }
135
    }
137
 
136
 
138
  /*************************
137
  /*************************
139
   * Handle v2 relocations *
138
   * Handle v2 relocations *
140
   *************************/
139
   *************************/
141
 
140
 
142
  /* Walk over header. */
141
  /* Walk over header. */
143
  r = (runtime_pseudo_reloc_item_v2 *) &v2_hdr[1];
142
  r = (runtime_pseudo_reloc_item_v2 *) &v2_hdr[1];
144
 
143
 
145
  for (; r < (runtime_pseudo_reloc_item_v2 *) end; r++)
144
  for (; r < (runtime_pseudo_reloc_item_v2 *) end; r++)
146
    {
145
    {
147
      /* location where new address will be written */
146
      /* location where new address will be written */
148
      reloc_target = (ptrdiff_t) base + r->target;
147
      reloc_target = (ptrdiff_t) base + r->target;
149
 
148
 
150
      /* get sym pointer. It points either to the iat entry
149
      /* get sym pointer. It points either to the iat entry
151
       * of the referenced element, or to the stub function.
150
       * of the referenced element, or to the stub function.
152
       */
151
       */
153
      addr_imp = (ptrdiff_t) base + r->sym;
152
      addr_imp = (ptrdiff_t) base + r->sym;
154
      addr_imp = *((ptrdiff_t *) addr_imp);
153
      addr_imp = *((ptrdiff_t *) addr_imp);
155
 
154
 
156
      /* read existing relocation value from image, casting to the
155
      /* read existing relocation value from image, casting to the
157
       * bitsize indicated by the 8 LSBs of flags. If the value is
156
       * bitsize indicated by the 8 LSBs of flags. If the value is
158
       * negative, manually sign-extend to ptrdiff_t width. Raise an
157
       * negative, manually sign-extend to ptrdiff_t width. Raise an
159
       * error if the bitsize indicated by the 8 LSBs of flags is not
158
       * error if the bitsize indicated by the 8 LSBs of flags is not
160
       * supported.
159
       * supported.
161
       */
160
       */
162
      switch ((r->flags & 0xff))
161
      switch ((r->flags & 0xff))
163
        {
162
        {
164
          case 8:
163
          case 8:
165
	    reldata = (ptrdiff_t) (*((unsigned char *)reloc_target));
164
	    reldata = (ptrdiff_t) (*((unsigned char *)reloc_target));
166
	    if ((reldata & 0x80) != 0)
165
	    if ((reldata & 0x80) != 0)
167
	      reldata |= ~((ptrdiff_t) 0xff);
166
	      reldata |= ~((ptrdiff_t) 0xff);
168
	    break;
167
	    break;
169
	  case 16:
168
	  case 16:
170
	    reldata = (ptrdiff_t) (*((unsigned short *)reloc_target));
169
	    reldata = (ptrdiff_t) (*((unsigned short *)reloc_target));
171
	    if ((reldata & 0x8000) != 0)
170
	    if ((reldata & 0x8000) != 0)
172
	      reldata |= ~((ptrdiff_t) 0xffff);
171
	      reldata |= ~((ptrdiff_t) 0xffff);
173
	    break;
172
	    break;
174
	  case 32:
173
	  case 32:
175
	    reldata = (ptrdiff_t) (*((unsigned int *)reloc_target));
174
	    reldata = (ptrdiff_t) (*((unsigned int *)reloc_target));
176
	    break;
175
	    break;
177
	  default:
176
	  default:
178
	    reldata=0;
177
	    reldata=0;
179
//        printf("  Unknown pseudo relocation bit size %d.\n",
178
//        printf("  Unknown pseudo relocation bit size %d.\n",
180
//           (int) (r->flags & 0xff));
179
//           (int) (r->flags & 0xff));
181
	    break;
180
	    break;
182
        }
181
        }
183
 
182
 
184
      /* Adjust the relocation value */
183
      /* Adjust the relocation value */
185
      reldata -= ((ptrdiff_t) base + r->sym);
184
      reldata -= ((ptrdiff_t) base + r->sym);
186
      reldata += addr_imp;
185
      reldata += addr_imp;
187
 
186
 
188
      /* Write the new relocation value back to *reloc_target */
187
      /* Write the new relocation value back to *reloc_target */
189
      switch ((r->flags & 0xff))
188
      switch ((r->flags & 0xff))
190
	{
189
	{
191
         case 8:
190
         case 8:
192
           *(uint8_t*)reloc_target = (uint8_t)reldata;
191
           *(uint8_t*)reloc_target = (uint8_t)reldata;
193
	   break;
192
	   break;
194
	 case 16:
193
	 case 16:
195
           *(uint16_t*)reloc_target = (uint16_t)reldata;
194
           *(uint16_t*)reloc_target = (uint16_t)reldata;
196
	   break;
195
	   break;
197
	 case 32:
196
	 case 32:
198
           *(uint32_t*)reloc_target = (uint32_t)reldata;
197
           *(uint32_t*)reloc_target = (uint32_t)reldata;
199
	   break;
198
	   break;
200
	}
199
	}
201
     }
200
     }
202
}
201
}
203
 
202
 
204
void
203
void
205
_pei386_runtime_relocator (void)
204
_pei386_runtime_relocator (void)
206
{
205
{
207
  static int was_init = 0;
206
  static int was_init = 0;
208
  if (was_init)
207
  if (was_init)
209
    return;
208
    return;
210
  ++was_init;
209
  ++was_init;
211
  do_pseudo_reloc (&__RUNTIME_PSEUDO_RELOC_LIST__,
210
  do_pseudo_reloc (&__RUNTIME_PSEUDO_RELOC_LIST__,
212
		   &__RUNTIME_PSEUDO_RELOC_LIST_END__,
211
		   &__RUNTIME_PSEUDO_RELOC_LIST_END__,
213
           &_image_base__);
212
           &_image_base__);
214
}
213
}