ReactOS 0.4.15-dev-7953-g1f49173
pseudo-reloc.c
Go to the documentation of this file.
1/* pseudo-reloc.c
2
3 Contributed by Egor Duda <deo@logos-m.ru>
4 Modified by addition of runtime_pseudo_reloc version 2
5 by Kai Tietz <kai.tietz@onevision.com>
6
7 THIS SOFTWARE IS NOT COPYRIGHTED
8
9 This source code is offered for use in the public domain. You may
10 use, modify or distribute it freely.
11
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
14 DISCLAMED. This includes but is not limited to warrenties of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16*/
17
18//#include <windows.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <stdarg.h>
22#include <memory.h>
23#include <internal.h>
24
25#if defined(__CYGWIN__)
26#include <wchar.h>
27#include <ntdef.h>
28#include <sys/cygwin.h>
29/* copied from winsup.h */
30# define NO_COPY __attribute__((nocommon)) __attribute__((section(".data_cygwin_nocopy")))
31/* custom status code: */
32#define STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION ((NTSTATUS) 0xe0000269)
33#define SHORT_MSG_BUF_SZ 128
34#else
35# define NO_COPY
36#endif
37
38#ifdef __GNUC__
39#define ATTRIBUTE_NORETURN __attribute__ ((noreturn))
40#else
41#define ATTRIBUTE_NORETURN
42#endif
43
44#ifndef __MINGW_LSYMBOL
45#define __MINGW_LSYMBOL(sym) sym
46#endif
47
50extern char __MINGW_LSYMBOL(_image_base__);
51
53
54/* v1 relocation is basically:
55 * *(base + .target) += .addend
56 * where (base + .target) is always assumed to point
57 * to a DWORD (4 bytes).
58 */
59typedef struct {
63
64/* v2 relocation is more complex. In effect, it is
65 * *(base + .target) += *(base + .sym) - (base + .sym)
66 * with care taken in both reading, sign extension, and writing
67 * because .flags may indicate that (base + .target) may point
68 * to a BYTE, WORD, DWORD, or QWORD (w64).
69 */
70typedef struct {
75
76typedef struct {
81
82static void ATTRIBUTE_NORETURN
83__report_error (const char *msg, ...)
84{
85#ifdef __CYGWIN__
86 /* This function is used to print short error messages
87 * to stderr, which may occur during DLL initialization
88 * while fixing up 'pseudo' relocations. This early, we
89 * may not be able to use cygwin stdio functions, so we
90 * use the win32 WriteFile api. This should work with both
91 * normal win32 console IO handles, redirected ones, and
92 * cygwin ptys.
93 */
94 char buf[SHORT_MSG_BUF_SZ];
95 wchar_t module[MAX_PATH];
96 char * posix_module = NULL;
97 static const char UNKNOWN_MODULE[] = "<unknown module>: ";
98 static const size_t UNKNOWN_MODULE_LEN = sizeof (UNKNOWN_MODULE) - 1;
99 static const char CYGWIN_FAILURE_MSG[] = "Cygwin runtime failure: ";
100 static const size_t CYGWIN_FAILURE_MSG_LEN = sizeof (CYGWIN_FAILURE_MSG) - 1;
101 DWORD len;
102 DWORD done;
105 ssize_t modulelen = GetModuleFileNameW (NULL, module, sizeof (module));
106
107 if (errh == INVALID_HANDLE_VALUE)
108 cygwin_internal (CW_EXIT_PROCESS,
109 STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION,
110 1);
111
112 if (modulelen > 0)
113 posix_module = cygwin_create_path (CCP_WIN_W_TO_POSIX, module);
114
115 va_start (args, msg);
116 len = (DWORD) vsnprintf (buf, SHORT_MSG_BUF_SZ, msg, args);
117 va_end (args);
118 buf[SHORT_MSG_BUF_SZ-1] = '\0'; /* paranoia */
119
120 if (posix_module)
121 {
122 WriteFile (errh, (PCVOID)CYGWIN_FAILURE_MSG,
123 CYGWIN_FAILURE_MSG_LEN, &done, NULL);
124 WriteFile (errh, (PCVOID)posix_module,
125 strlen(posix_module), &done, NULL);
126 WriteFile (errh, (PCVOID)": ", 2, &done, NULL);
127 WriteFile (errh, (PCVOID)buf, len, &done, NULL);
128 free (posix_module);
129 }
130 else
131 {
132 WriteFile (errh, (PCVOID)CYGWIN_FAILURE_MSG,
133 CYGWIN_FAILURE_MSG_LEN, &done, NULL);
134 WriteFile (errh, (PCVOID)UNKNOWN_MODULE,
135 UNKNOWN_MODULE_LEN, &done, NULL);
136 WriteFile (errh, (PCVOID)buf, len, &done, NULL);
137 }
138 WriteFile (errh, (PCVOID)"\n", 1, &done, NULL);
139
140 cygwin_internal (CW_EXIT_PROCESS,
141 STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION,
142 1);
143 /* not reached, but silences noreturn warning */
144 abort ();
145#else
146 va_list argp;
147 va_start (argp, msg);
148# ifdef __MINGW64_VERSION_MAJOR
149 __mingw_fprintf (stderr, "Mingw-w64 runtime failure:\n");
150 __mingw_vfprintf (stderr, msg, argp);
151# else
152 fprintf (stderr, "Mingw runtime failure:\n");
153 vfprintf (stderr, msg, argp);
154#endif
155 va_end (argp);
156 abort ();
157#endif
158}
159
160/* For mingw-w64 we have additional helpers to get image information
161 on runtime. This allows us to cache for pseudo-relocation pass
162 the temporary access of code/read-only sections.
163 This step speeds up pseudo-relocation pass. */
164#ifdef __MINGW64_VERSION_MAJOR
165extern int __mingw_GetSectionCount (void);
167extern PBYTE _GetPEImageBase (void);
168
169typedef struct sSecInfo {
170 /* Keeps altered section flags, or zero if nothing was changed. */
171 DWORD old_protect;
172 PBYTE sec_start;
174} sSecInfo;
175
176static sSecInfo *the_secs = NULL;
177static int maxSections = 0;
178
179static void
180mark_section_writable (LPVOID addr)
181{
184 int i;
185
186 for (i = 0; i < maxSections; i++)
187 {
188 if (the_secs[i].sec_start <= ((LPBYTE) addr)
189 && ((LPBYTE) addr) < (the_secs[i].sec_start + the_secs[i].hash->Misc.VirtualSize))
190 return;
191 }
193 if (!h)
194 {
195 __report_error ("Address %p has no image-section", addr);
196 return;
197 }
198 the_secs[i].hash = h;
199 the_secs[i].old_protect = 0;
200 the_secs[i].sec_start = _GetPEImageBase () + h->VirtualAddress;
201
202 if (!VirtualQuery (the_secs[i].sec_start, &b, sizeof(b)))
203 {
204 __report_error (" VirtualQuery failed for %d bytes at address %p",
205 (int) h->Misc.VirtualSize, the_secs[i].sec_start);
206 return;
207 }
208
209 if (b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE)
210 {
211 if (!VirtualProtect (b.BaseAddress, b.RegionSize,
213 &the_secs[i].old_protect))
214 __report_error (" VirtualProtect failed with code 0x%x",
215 (int) GetLastError ());
216 }
217 ++maxSections;
218 return;
219}
220
221static void
222restore_modified_sections (void)
223{
224 int i;
226 DWORD oldprot;
227
228 for (i = 0; i < maxSections; i++)
229 {
230 if (the_secs[i].old_protect == 0)
231 continue;
232 if (!VirtualQuery (the_secs[i].sec_start, &b, sizeof(b)))
233 {
234 __report_error (" VirtualQuery failed for %d bytes at address %p",
235 (int) the_secs[i].hash->Misc.VirtualSize,
236 the_secs[i].sec_start);
237 return;
238 }
239 VirtualProtect (b.BaseAddress, b.RegionSize, the_secs[i].old_protect,
240 &oldprot);
241 }
242}
243
244#endif /* __MINGW64_VERSION_MAJOR */
245
246/* This function temporarily marks the page containing addr
247 * writable, before copying len bytes from *src to *addr, and
248 * then restores the original protection settings to the page.
249 *
250 * Using this function eliminates the requirement with older
251 * pseudo-reloc implementations, that sections containing
252 * pseudo-relocs (such as .text and .rdata) be permanently
253 * marked writable. This older behavior sabotaged any memory
254 * savings achieved by shared libraries on win32 -- and was
255 * slower, too. However, on cygwin as of binutils 2.20 the
256 * .text section is still marked writable, and the .rdata section
257 * is folded into the (writable) .data when --enable-auto-import.
258 */
259static void
260__write_memory (void *addr, const void *src, size_t len)
261{
263 DWORD oldprot;
264 int call_unprotect = 0;
265
266 if (!len)
267 return;
268
269#ifdef __MINGW64_VERSION_MAJOR
270 mark_section_writable ((LPVOID) addr);
271#endif
272
273 if (!VirtualQuery (addr, &b, sizeof(b)))
274 {
275 __report_error (" VirtualQuery failed for %d bytes at address %p",
276 (int) sizeof(b), addr);
277 }
278
279 /* Temporarily allow write access to read-only protected memory. */
280 if (b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE)
281 {
282 call_unprotect = 1;
283 VirtualProtect (b.BaseAddress, b.RegionSize, PAGE_EXECUTE_READWRITE,
284 &oldprot);
285 }
286
287 /* write the data. */
288 memcpy (addr, src, len);
289 /* Restore original protection. */
290 if (call_unprotect && b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE)
291 VirtualProtect (b.BaseAddress, b.RegionSize, oldprot, &oldprot);
292}
293
294#define RP_VERSION_V1 0
295#define RP_VERSION_V2 1
296
297static void
298do_pseudo_reloc (void * start, void * end, void * base)
299{
300 ptrdiff_t addr_imp, reldata;
301 ptrdiff_t reloc_target = (ptrdiff_t) ((char *)end - (char*)start);
304
305 /* A valid relocation list will contain at least one entry, and
306 * one v1 data structure (the smallest one) requires two DWORDs.
307 * So, if the relocation list is smaller than 8 bytes, bail.
308 */
309 if (reloc_target < 8)
310 return;
311
312 /* Check if this is the old pseudo relocation version. */
313 /* There are two kinds of v1 relocation lists:
314 * 1) With a (v2-style) version header. In this case, the
315 * first entry in the list is a 3-DWORD structure, with
316 * value:
317 * { 0, 0, RP_VERSION_V1 }
318 * In this case, we skip to the next entry in the list,
319 * knowing that all elements after the head item can
320 * be cast to runtime_pseudo_reloc_item_v1.
321 * 2) Without a (v2-style) version header. In this case, the
322 * first element in the list IS an actual v1 relocation
323 * record, which is two DWORDs. Because there will never
324 * be a case where a v1 relocation record has both
325 * addend == 0 and target == 0, this case will not be
326 * confused with the prior one.
327 * All current binutils, when generating a v1 relocation list,
328 * use the second (e.g. original) form -- that is, without the
329 * v2-style version header.
330 */
331 if (reloc_target >= 12
332 && v2_hdr->magic1 == 0 && v2_hdr->magic2 == 0
333 && v2_hdr->version == RP_VERSION_V1)
334 {
335 /* We have a list header item indicating that the rest
336 * of the list contains v1 entries. Move the pointer to
337 * the first true v1 relocation record. By definition,
338 * that v1 element will not have both addend == 0 and
339 * target == 0 (and thus, when interpreted as a
340 * runtime_pseudo_reloc_v2, it will not have both
341 * magic1 == 0 and magic2 == 0).
342 */
343 v2_hdr++;
344 }
345
346 if (v2_hdr->magic1 != 0 || v2_hdr->magic2 != 0)
347 {
348 /*************************
349 * Handle v1 relocations *
350 *************************/
352 for (o = (runtime_pseudo_reloc_item_v1 *) v2_hdr;
354 o++)
355 {
356 DWORD newval;
357 reloc_target = (ptrdiff_t) base + o->target;
358 newval = (*((DWORD*) reloc_target)) + o->addend;
359 __write_memory ((void *) reloc_target, &newval, sizeof(DWORD));
360 }
361 return;
362 }
363
364 /* If we got this far, then we have relocations of version 2 or newer */
365
366 /* Check if this is a known version. */
367 if (v2_hdr->version != RP_VERSION_V2)
368 {
369 __report_error (" Unknown pseudo relocation protocol version %d.\n",
370 (int) v2_hdr->version);
371 return;
372 }
373
374 /*************************
375 * Handle v2 relocations *
376 *************************/
377
378 /* Walk over header. */
379 r = (runtime_pseudo_reloc_item_v2 *) &v2_hdr[1];
380
381 for (; r < (runtime_pseudo_reloc_item_v2 *) end; r++)
382 {
383 /* location where new address will be written */
384 reloc_target = (ptrdiff_t) base + r->target;
385
386 /* get sym pointer. It points either to the iat entry
387 * of the referenced element, or to the stub function.
388 */
389 addr_imp = (ptrdiff_t) base + r->sym;
390 addr_imp = *((ptrdiff_t *) addr_imp);
391
392 /* read existing relocation value from image, casting to the
393 * bitsize indicated by the 8 LSBs of flags. If the value is
394 * negative, manually sign-extend to ptrdiff_t width. Raise an
395 * error if the bitsize indicated by the 8 LSBs of flags is not
396 * supported.
397 */
398 switch ((r->flags & 0xff))
399 {
400 case 8:
401 reldata = (ptrdiff_t) (*((unsigned char *)reloc_target));
402 if ((reldata & 0x80) != 0)
403 reldata |= ~((ptrdiff_t) 0xff);
404 break;
405 case 16:
406 reldata = (ptrdiff_t) (*((unsigned short *)reloc_target));
407 if ((reldata & 0x8000) != 0)
408 reldata |= ~((ptrdiff_t) 0xffff);
409 break;
410 case 32:
411 reldata = (ptrdiff_t) (*((unsigned int *)reloc_target));
412#ifdef _WIN64
413 if ((reldata & 0x80000000) != 0)
414 reldata |= ~((ptrdiff_t) 0xffffffff);
415#endif
416 break;
417#ifdef _WIN64
418 case 64:
419 reldata = (ptrdiff_t) (*((unsigned long long *)reloc_target));
420 break;
421#endif
422 default:
423 reldata=0;
424 __report_error (" Unknown pseudo relocation bit size %d.\n",
425 (int) (r->flags & 0xff));
426 break;
427 }
428
429 /* Adjust the relocation value */
430 reldata -= ((ptrdiff_t) base + r->sym);
431 reldata += addr_imp;
432
433 /* Write the new relocation value back to *reloc_target */
434 switch ((r->flags & 0xff))
435 {
436 case 8:
437 __write_memory ((void *) reloc_target, &reldata, 1);
438 break;
439 case 16:
440 __write_memory ((void *) reloc_target, &reldata, 2);
441 break;
442 case 32:
443 __write_memory ((void *) reloc_target, &reldata, 4);
444 break;
445#ifdef _WIN64
446 case 64:
447 __write_memory ((void *) reloc_target, &reldata, 8);
448 break;
449#endif
450 }
451 }
452}
453
454void
456{
457 static NO_COPY int was_init = 0;
458#ifdef __MINGW64_VERSION_MAJOR
459 int mSecs;
460#endif /* __MINGW64_VERSION_MAJOR */
461
462 if (was_init)
463 return;
464 ++was_init;
465#ifdef __MINGW64_VERSION_MAJOR
466 mSecs = __mingw_GetSectionCount ();
467 the_secs = (sSecInfo *) alloca (sizeof (sSecInfo) * (size_t) mSecs);
468 maxSections = 0;
469#endif /* __MINGW64_VERSION_MAJOR */
470
473#ifdef __GNUC__
474 &__MINGW_LSYMBOL(_image_base__)
475#else
477#endif
478 );
479#ifdef __MINGW64_VERSION_MAJOR
480 restore_modified_sections ();
481#endif /* __MINGW64_VERSION_MAJOR */
482}
#define __GNUC__
Definition: _icc.h:38
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * va_list
Definition: acmsvcex.h:78
#define va_end(ap)
Definition: acmsvcex.h:90
#define va_start(ap, A)
Definition: acmsvcex.h:91
#define msg(x)
Definition: auth_time.c:54
HANDLE WINAPI GetStdHandle(IN DWORD nStdHandle)
Definition: console.c:203
CONST VOID * PCVOID
Definition: cfgmgr32.h:44
#define __ImageBase
Definition: crt_handler.c:22
PBYTE _GetPEImageBase(void)
Definition: pesect.c:163
#define free
Definition: debug_ros.c:5
#define NULL
Definition: types.h:112
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define MAX_PATH
Definition: compat.h:34
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
DWORD WINAPI GetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize)
Definition: loader.c:600
__kernel_size_t size_t
Definition: linux.h:237
__kernel_ptrdiff_t ptrdiff_t
Definition: linux.h:247
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint start
Definition: gl.h:1545
GLuint GLuint end
Definition: gl.h:1545
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLenum src
Definition: glext.h:6340
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLenum const GLvoid * addr
Definition: glext.h:9621
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define abort()
Definition: i386-dis.c:34
#define stderr
Definition: stdio.h:100
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
_Check_return_opt_ _CRTIMP int __cdecl vfprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format, va_list _ArgList)
#define b
Definition: ke_i.h:79
#define alloca
Definition: malloc.h:357
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define PAGE_READWRITE
Definition: nt_native.h:1304
#define DWORD
Definition: nt_native.h:44
#define PAGE_EXECUTE_READWRITE
Definition: nt_native.h:1308
BYTE * PBYTE
Definition: pedump.c:66
PIMAGE_SECTION_HEADER __mingw_GetSectionForAddress(LPVOID p)
Definition: pesect.c:101
int __mingw_GetSectionCount(void)
Definition: pesect.c:115
#define NO_COPY
Definition: pseudo-reloc.c:35
static void __write_memory(void *addr, const void *src, size_t len)
Definition: pseudo-reloc.c:260
char __RUNTIME_PSEUDO_RELOC_LIST_END__
#define __MINGW_LSYMBOL(sym)
Definition: pseudo-reloc.c:45
void _pei386_runtime_relocator(void)
Definition: pseudo-reloc.c:455
char __RUNTIME_PSEUDO_RELOC_LIST__
static void do_pseudo_reloc(void *start, void *end, void *base)
Definition: pseudo-reloc.c:298
#define RP_VERSION_V1
Definition: pseudo-reloc.c:294
#define RP_VERSION_V2
Definition: pseudo-reloc.c:295
static void ATTRIBUTE_NORETURN __report_error(const char *msg,...)
Definition: pseudo-reloc.c:83
#define ATTRIBUTE_NORETURN
Definition: pseudo-reloc.c:41
int ssize_t
Definition: rosdhcp.h:48
#define args
Definition: format.c:66
Definition: match.c:390
Definition: _hash_fun.h:40
#define vsnprintf
Definition: tif_win32.c:406
unsigned char * LPBYTE
Definition: typedefs.h:53
BOOL NTAPI VirtualProtect(IN LPVOID lpAddress, IN SIZE_T dwSize, IN DWORD flNewProtect, OUT PDWORD lpflOldProtect)
Definition: virtmem.c:135
SIZE_T NTAPI VirtualQuery(IN LPCVOID lpAddress, OUT PMEMORY_BASIC_INFORMATION lpBuffer, IN SIZE_T dwLength)
Definition: virtmem.c:211
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define STD_ERROR_HANDLE
Definition: winbase.h:269