From b98d4953348edf8a9a04b8e69b4accd87c378b35 Mon Sep 17 00:00:00 2001 From: "Sergey Semyonov (Serge)" Date: Mon, 14 Mar 2011 20:15:36 +0000 Subject: [PATCH] newlib: fix pseudo relocations git-svn-id: svn://kolibrios.org@1908 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/develop/libraries/newlib/Makefile | 4 +- .../develop/libraries/newlib/crt/chkstk.S | 2 + .../develop/libraries/newlib/crt/crt_amz.S | 1 + .../libraries/newlib/crt/pseudo-reloc.S | 26 --- .../libraries/newlib/crt/pseudo-reloc.c | 214 ++++++++++++++++++ .../develop/libraries/newlib/crt/thread.S | 2 + programs/develop/libraries/newlib/pe_app.lds | 43 ++-- programs/develop/libraries/newlib/time/time.c | 8 + 8 files changed, 249 insertions(+), 51 deletions(-) delete mode 100644 programs/develop/libraries/newlib/crt/pseudo-reloc.S create mode 100644 programs/develop/libraries/newlib/crt/pseudo-reloc.c diff --git a/programs/develop/libraries/newlib/Makefile b/programs/develop/libraries/newlib/Makefile index 4b998c2f9b..99037a380d 100644 --- a/programs/develop/libraries/newlib/Makefile +++ b/programs/develop/libraries/newlib/Makefile @@ -17,7 +17,7 @@ AMZ_SRCS:= \ crt/crt_amz.S \ crt/chkstk.S \ crt/exit.S \ - crt/pseudo-reloc.S \ + crt/pseudo-reloc.c \ crt/setjmp.S STATIC_SRCS:= \ @@ -267,7 +267,7 @@ MATH_SRCS = acosf.c acosh.c acoshf.c acoshl.c acosl.c asinf.c asinh.c asinhf.c sinf.S sinl.S tan.S tanf.S tanl.S s_expm1.S -AMZ_OBJS = $(patsubst %.S, %.o, $(AMZ_SRCS)) +AMZ_OBJS = $(patsubst %.S, %.o, $(patsubst %.c, %.o, $(AMZ_SRCS))) STATIC_OBJS = $(patsubst %.S, %.o, $(patsubst %.c, %.o, $(STATIC_SRCS))) diff --git a/programs/develop/libraries/newlib/crt/chkstk.S b/programs/develop/libraries/newlib/crt/chkstk.S index a1c6a4f68e..1b9cc33878 100644 --- a/programs/develop/libraries/newlib/crt/chkstk.S +++ b/programs/develop/libraries/newlib/crt/chkstk.S @@ -4,6 +4,8 @@ .section .text +.def ___chkstk; .scl 2; .type 32; .endef +.def __alloca; .scl 2; .type 32; .endef ___chkstk: __alloca: pushl %ecx /* save temp */ diff --git a/programs/develop/libraries/newlib/crt/crt_amz.S b/programs/develop/libraries/newlib/crt/crt_amz.S index 4a8865687d..72bbfb79b0 100644 --- a/programs/develop/libraries/newlib/crt/crt_amz.S +++ b/programs/develop/libraries/newlib/crt/crt_amz.S @@ -6,6 +6,7 @@ .align 4 __start: + call __pei386_runtime_relocator jmp _main .align 4 diff --git a/programs/develop/libraries/newlib/crt/pseudo-reloc.S b/programs/develop/libraries/newlib/crt/pseudo-reloc.S deleted file mode 100644 index cf7387d182..0000000000 --- a/programs/develop/libraries/newlib/crt/pseudo-reloc.S +++ /dev/null @@ -1,26 +0,0 @@ - -.global __pei386_runtime_relocator - -.text - -__pei386_runtime_relocator: - -# movl $___RUNTIME_PSEUDO_RELOC_LIST__, %ecx - -# pushl %ebp -# cmpl $___RUNTIME_PSEUDO_RELOC_LIST_END__, %ecx -# movl %esp, %ebp -# jnb .L2 - -#.L1: -# movl (%ecx), %eax -# movl 4(%ecx), %edx -# addl $8, %ecx -# addl %eax, __image_base__(%edx) -# cmpl $___RUNTIME_PSEUDO_RELOC_LIST_END__, %ecx -# jb .L1 - -#.L2: -# popl %ebp - ret - diff --git a/programs/develop/libraries/newlib/crt/pseudo-reloc.c b/programs/develop/libraries/newlib/crt/pseudo-reloc.c new file mode 100644 index 0000000000..67685f12c1 --- /dev/null +++ b/programs/develop/libraries/newlib/crt/pseudo-reloc.c @@ -0,0 +1,214 @@ +/* pseudo-reloc.c + + Contributed by Egor Duda + Modified by addition of runtime_pseudo_reloc version 2 + by Kai Tietz + + THIS SOFTWARE IS NOT COPYRIGHTED + + This source code is offered for use in the public domain. You may + use, modify or distribute it freely. + + This code is distributed in the hope that it will be useful but + WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY + DISCLAMED. This includes but is not limited to warrenties of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + +#include +#include +#include +#include +#include + +extern char __RUNTIME_PSEUDO_RELOC_LIST__; +extern char __RUNTIME_PSEUDO_RELOC_LIST_END__; +extern char _image_base__; + +void _pei386_runtime_relocator (void); + +/* v1 relocation is basically: + * *(base + .target) += .addend + * where (base + .target) is always assumed to point + * to a DWORD (4 bytes). + */ +typedef struct { + uint32_t addend; + uint32_t target; +} runtime_pseudo_reloc_item_v1; + +/* v2 relocation is more complex. In effect, it is + * *(base + .target) += *(base + .sym) - (base + .sym) + * with care taken in both reading, sign extension, and writing + * because .flags may indicate that (base + .target) may point + * to a BYTE, WORD, DWORD, or QWORD (w64). + */ +typedef struct { + uint32_t sym; + uint32_t target; + uint32_t flags; +} runtime_pseudo_reloc_item_v2; + +typedef struct { + uint32_t magic1; + uint32_t magic2; + uint32_t version; +} runtime_pseudo_reloc_v2; + +#define RP_VERSION_V1 0 +#define RP_VERSION_V2 1 + +static void +do_pseudo_reloc (void * start, void * end, void * base) +{ + ptrdiff_t addr_imp, reldata; + ptrdiff_t reloc_target = (ptrdiff_t) ((char *)end - (char*)start); + runtime_pseudo_reloc_v2 *v2_hdr = (runtime_pseudo_reloc_v2 *) start; + runtime_pseudo_reloc_item_v2 *r; + + /* A valid relocation list will contain at least one entry, and + * one v1 data structure (the smallest one) requires two DWORDs. + * So, if the relocation list is smaller than 8 bytes, bail. + */ + if (reloc_target < 8) + return; + + /* Check if this is the old pseudo relocation version. */ + /* There are two kinds of v1 relocation lists: + * 1) With a (v2-style) version header. In this case, the + * first entry in the list is a 3-DWORD structure, with + * value: + * { 0, 0, RP_VERSION_V1 } + * In this case, we skip to the next entry in the list, + * knowing that all elements after the head item can + * be cast to runtime_pseudo_reloc_item_v1. + * 2) Without a (v2-style) version header. In this case, the + * first element in the list IS an actual v1 relocation + * record, which is two DWORDs. Because there will never + * be a case where a v1 relocation record has both + * addend == 0 and target == 0, this case will not be + * confused with the prior one. + * All current binutils, when generating a v1 relocation list, + * use the second (e.g. original) form -- that is, without the + * v2-style version header. + */ + if (reloc_target >= 12 + && v2_hdr->magic1 == 0 && v2_hdr->magic2 == 0 + && v2_hdr->version == RP_VERSION_V1) + { + /* We have a list header item indicating that the rest + * of the list contains v1 entries. Move the pointer to + * the first true v1 relocation record. By definition, + * that v1 element will not have both addend == 0 and + * target == 0 (and thus, when interpreted as a + * runtime_pseudo_reloc_v2, it will not have both + * magic1 == 0 and magic2 == 0). + */ + v2_hdr++; + } + + if (v2_hdr->magic1 != 0 || v2_hdr->magic2 != 0) + { + /************************* + * Handle v1 relocations * + *************************/ + runtime_pseudo_reloc_item_v1 * o; + for (o = (runtime_pseudo_reloc_item_v1 *) v2_hdr; + o < (runtime_pseudo_reloc_item_v1 *)end; + o++) + { + uint32_t newval; + reloc_target = (ptrdiff_t) base + o->target; + newval = (*((uint32_t*) reloc_target)) + o->addend; + *(uint32_t*)reloc_target = newval; + } + return; + } + + /* If we got this far, then we have relocations of version 2 or newer */ + + /* Check if this is a known version. */ + if (v2_hdr->version != RP_VERSION_V2) + { + printf(" Unknown pseudo relocation protocol version %d.\n", + (int) v2_hdr->version); + return; + } + + /************************* + * Handle v2 relocations * + *************************/ + + /* Walk over header. */ + r = (runtime_pseudo_reloc_item_v2 *) &v2_hdr[1]; + + for (; r < (runtime_pseudo_reloc_item_v2 *) end; r++) + { + /* location where new address will be written */ + reloc_target = (ptrdiff_t) base + r->target; + + /* get sym pointer. It points either to the iat entry + * of the referenced element, or to the stub function. + */ + addr_imp = (ptrdiff_t) base + r->sym; + addr_imp = *((ptrdiff_t *) addr_imp); + + /* read existing relocation value from image, casting to the + * bitsize indicated by the 8 LSBs of flags. If the value is + * negative, manually sign-extend to ptrdiff_t width. Raise an + * error if the bitsize indicated by the 8 LSBs of flags is not + * supported. + */ + switch ((r->flags & 0xff)) + { + case 8: + reldata = (ptrdiff_t) (*((unsigned char *)reloc_target)); + if ((reldata & 0x80) != 0) + reldata |= ~((ptrdiff_t) 0xff); + break; + case 16: + reldata = (ptrdiff_t) (*((unsigned short *)reloc_target)); + if ((reldata & 0x8000) != 0) + reldata |= ~((ptrdiff_t) 0xffff); + break; + case 32: + reldata = (ptrdiff_t) (*((unsigned int *)reloc_target)); + break; + default: + reldata=0; + printf(" Unknown pseudo relocation bit size %d.\n", + (int) (r->flags & 0xff)); + break; + } + + /* Adjust the relocation value */ + reldata -= ((ptrdiff_t) base + r->sym); + reldata += addr_imp; + + /* Write the new relocation value back to *reloc_target */ + switch ((r->flags & 0xff)) + { + case 8: + *(uint8_t*)reloc_target = (uint8_t)reldata; + break; + case 16: + *(uint16_t*)reloc_target = (uint16_t)reldata; + break; + case 32: + *(uint32_t*)reloc_target = (uint32_t)reldata; + break; + } + } +} + +void +_pei386_runtime_relocator (void) +{ + static int was_init = 0; + if (was_init) + return; + ++was_init; + do_pseudo_reloc (&__RUNTIME_PSEUDO_RELOC_LIST__, + &__RUNTIME_PSEUDO_RELOC_LIST_END__, + &_image_base__); +} diff --git a/programs/develop/libraries/newlib/crt/thread.S b/programs/develop/libraries/newlib/crt/thread.S index d8400b7ecf..12f1d1fdcc 100644 --- a/programs/develop/libraries/newlib/crt/thread.S +++ b/programs/develop/libraries/newlib/crt/thread.S @@ -4,6 +4,8 @@ .section .text +.def _create_thread; .scl 2; .type 32; .endef + .align 4 _create_thread: #.thr_proc equ esp+8 diff --git a/programs/develop/libraries/newlib/pe_app.lds b/programs/develop/libraries/newlib/pe_app.lds index 7220c4c78d..316761263b 100644 --- a/programs/develop/libraries/newlib/pe_app.lds +++ b/programs/develop/libraries/newlib/pe_app.lds @@ -10,7 +10,6 @@ SECTIONS .text __image_base__ + . : { - *(.init) *(.text) *(SORT(.text$*)) @@ -26,10 +25,7 @@ SECTIONS *(.gcc_exc) PROVIDE (etext = .); *(.gcc_except_table) - } - .rdata ALIGN(__section_alignment__): - { *(.rdata) *(SORT(.rdata$*)) ___RUNTIME_PSEUDO_RELOC_LIST__ = .; @@ -37,7 +33,26 @@ SECTIONS *(.rdata_runtime_pseudo_reloc) ___RUNTIME_PSEUDO_RELOC_LIST_END__ = .; __RUNTIME_PSEUDO_RELOC_LIST_END__ = .; - } + } + .data ALIGN(__section_alignment__): + { + PROVIDE ( __data_start__ = .) ; + *(.data) + *(.data2) + *(SORT(.data$*)) + *(.jcr) + __CRT_MT = .; + LONG(0); + PROVIDE ( __data_end__ = .) ; + *(.data_cygwin_nocopy) + } + + .eh_frame ALIGN(__section_alignment__): + { + *(.eh_frame) + ___iend = . ; + } + .CRT ALIGN(__section_alignment__): { ___crt_xc_start__ = . ; @@ -57,24 +72,6 @@ SECTIONS ___crt_xt_end__ = . ; } - .data ALIGN(__section_alignment__): - { - PROVIDE ( __data_start__ = .) ; - *(.data) - *(.data2) - *(SORT(.data$*)) - *(.jcr) - __CRT_MT = .; - LONG(0); - PROVIDE ( __data_end__ = .) ; - *(.data_cygwin_nocopy) - } - - .eh_frame ALIGN(__section_alignment__): - { - *(.eh_frame) - ___iend = . ; - } .bss ALIGN(__section_alignment__): { diff --git a/programs/develop/libraries/newlib/time/time.c b/programs/develop/libraries/newlib/time/time.c index 58f06324f6..dde5a65731 100644 --- a/programs/develop/libraries/newlib/time/time.c +++ b/programs/develop/libraries/newlib/time/time.c @@ -51,3 +51,11 @@ _DEFUN (time, (t), } return -1; } + +int +_DEFUN (gettimeofday, (ptimeval, ptimezone), + struct timeval *ptimeval _AND + void *ptimezone) +{ + return _gettimeofday_r (_REENT, ptimeval, ptimezone); +}