Subversion Repositories Kolibri OS

Rev

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

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