From 489258eef2b8c36a8fe6f15d92d7df04d8aebaf8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Alejandro=20R=2E=20Sede=C3=B1o?= Date: Sun, 18 Mar 2007 17:57:05 +0000 Subject: [PATCH 1/1] Greg Parker's Palm Elf Arm Loader (PEAL) http://www.sealiesoftware.com/peal/ --- README.txt | 399 ++++++++++++++++++ arm/pealstub.c | 85 ++++ arm/pealstub.h | 41 ++ example/Makefile | 28 ++ example/arm/Makefile | 15 + example/arm/arm.c | 45 ++ example/arm/arm2.c | 14 + example/m68k.c | 158 +++++++ example/pealexample.def | 2 + example/pealexample.rcp | 6 + m68k/elf.h | 91 ++++ m68k/elf32.h | 157 +++++++ m68k/elf_common.h | 299 +++++++++++++ m68k/peal.c | 905 ++++++++++++++++++++++++++++++++++++++++ m68k/peal.h | 109 +++++ postlink/Makefile | 22 + postlink/complain.cc | 78 ++++ postlink/complain.h | 33 ++ postlink/elf.h | 91 ++++ postlink/elf32.h | 157 +++++++ postlink/elf_common.h | 299 +++++++++++++ postlink/got.h | 93 +++++ postlink/image.cc | 478 +++++++++++++++++++++ postlink/image.h | 67 +++ postlink/peal-postlink | Bin 0 -> 743725 bytes postlink/postlinker.cc | 256 ++++++++++++ postlink/postlinker.h | 30 ++ postlink/relocation.cc | 67 +++ postlink/relocation.h | 55 +++ postlink/section.cc | 334 +++++++++++++++ postlink/section.h | 129 ++++++ postlink/stringtable.h | 91 ++++ postlink/swap.h | 104 +++++ postlink/symbol.cc | 91 ++++ postlink/symbol.h | 66 +++ postlink/symboltable.cc | 109 +++++ postlink/symboltable.h | 66 +++ 37 files changed, 5070 insertions(+) create mode 100644 README.txt create mode 100644 arm/pealstub.c create mode 100644 arm/pealstub.h create mode 100644 example/Makefile create mode 100644 example/arm/Makefile create mode 100644 example/arm/arm.c create mode 100644 example/arm/arm2.c create mode 100644 example/m68k.c create mode 100644 example/pealexample.def create mode 100644 example/pealexample.rcp create mode 100644 m68k/elf.h create mode 100644 m68k/elf32.h create mode 100644 m68k/elf_common.h create mode 100644 m68k/peal.c create mode 100644 m68k/peal.h create mode 100644 postlink/Makefile create mode 100644 postlink/complain.cc create mode 100644 postlink/complain.h create mode 100644 postlink/elf.h create mode 100644 postlink/elf32.h create mode 100644 postlink/elf_common.h create mode 100644 postlink/got.h create mode 100644 postlink/image.cc create mode 100644 postlink/image.h create mode 100755 postlink/peal-postlink create mode 100644 postlink/postlinker.cc create mode 100644 postlink/postlinker.h create mode 100644 postlink/relocation.cc create mode 100644 postlink/relocation.h create mode 100644 postlink/section.cc create mode 100644 postlink/section.h create mode 100644 postlink/stringtable.h create mode 100644 postlink/swap.h create mode 100644 postlink/symbol.cc create mode 100644 postlink/symbol.h create mode 100644 postlink/symboltable.cc create mode 100644 postlink/symboltable.h diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..7acb173 --- /dev/null +++ b/README.txt @@ -0,0 +1,399 @@ +Peal: Palm ELF ARM Loader +version 2005-4-14 + +Peal is a simple ELF postlinker and loader for Palm OS. It allows ARM +code to use global variables and function pointers without restriction. + +http://www.sealiesoftware.com/peal/ + + +FEATURES + +Features supported by Peal and Peal-loaded ARM code: + +* Global variables + +* Function pointers + +* Automatic handling of code segments larger than 64 KB + +* Multiple entry point functions + +* Access to global variables from m68k code + +* Minimum memory usage - code and read-only data are not copied to + feature memory or the heap + +* Thumb and ARM/Thumb interworking + + +LIMITATIONS + +* Peal is substantially UNTESTED. It may crash, generate incorrect + ARM global data, or modify random memory locations at runtime. + +* Peal has some support for C++ code, but it is even less tested. + +* Peal does not provide support for arbitrary ARM-ELF code. Only + code built with Peal's postlinker can be loaded by Peal. + +* Peal does not provide support for ELF shared libraries. + +* Peal uses the stack space provided by PceNativeCall(), which is + only 4 KB by default. There are ways to increase the ARM stack size, + but Peal does not use any of them. + + +USAGE + +A synopsis of Peal usage follows. See the example/ directory for a simple +demonstration, and the rest of this README for complete details. + +0. Build the peal-postlink program in the postlink/ directory: + `cd postlink; make` + +1. Write ARM code that uses global data or function pointers. ARM + functions intended to be called by m68k code may take a single + parameter. ARM functions that need to call back into m68k code should + use the variables gEmulStateP and gCall68KFuncP from arm/pealstub.h. + unsigned long MyArmFunction(void *arg) { ... } + +2. Write m68k code that uses the API in m68k/peal.h to load ARM code + and call ARM functions: + PealModule m = PealLoadFromResources('armc', 1000); + void *address = PealLookupSymbol(m, "MyArmFunction"); + unsigned long result = PealCall(m, address, myArg); + PealUnload(m); + +3. Compile m68k/peal.c along with other m68k code. + +4. Add -fPIC when compiling to compile all ARM code as position-independent: + `arm-palmos-gcc -fPIC ...` + Compile arm/pealstub.c along with other ARM code. + +5. Add --emit-relocs when linking ARM code to preserve relocation information: + `arm-palmos-ld --emit-relocs ...` + or `arm-palmos-gcc -Wl,--emit-relocs ...` + +6. Run the Peal postlinker to generate ARM code resources: + `peal-postlink -s 1000 -t armc -o postlinked-rsrcs.ro linked-binary.bin` + +7. Add the resources generated by peal-postlink to your Palm program as usual. + + +LARGE CODE + +Palm OS limits resources to somewhat less than 64 KB each. There are +two ways to use Peal with code or initialized data larger than 64 KB. + +1. Use ld's `--split-by-file` option to split the code into segments + smaller than 64 KB each. Then use `peal-postlink -s ...` + to place each segment into its own Palm resource. Finally, load + the code with PealLoadFromResources(). + + `arm-palmos-ld --split-by-file=64000 ...` + or `arm-palmos-gcc -Wl,--split-by-file=64000` + + This method is fully automatic with Peal. No manual segmentation + or code reassembly is needed. This method also takes the minimum + amount of memory, because PealLoadFromResources() does not need + to copy the code into feature memory or the heap. + + Cross-segment function calls are somewhat less efficient that + intra-segment calls. For maximum performance, order the files on + the link line so files that call each other are close together. + Alternatively, use __attribute__((section(...))) to segment by hand. + + For very large source files or large data segments, `--split-by-file` + may still generate segments larger than 64000 bytes. In this case, + Peal automatically splits the segment across multiple resources, + and reassembles it during PealLoadFromResources(). Note that + peal-postlink will warn you that the large segment will require + more memory at runtime, because the reassembled section is + allocated on the dynamic heap and the reassembly process + itself temporarily uses additional heap memory. + +2. Build the code and data as one big binary, using peal-postlink + without the -s option. Split the binary into multiple code resources. + Then reassemble the code resources into a single block in feature + memory or on the heap. Finally, load the code with PealLoad(). + + This method consumes twice as much memory, and Peal provides no + special support for this reassembly. + + +C++ COMPATIBILITY + +Peal provides support for C++ static constructors and destructors. +By default, the static constructors are run during the first +PealCall(), and the static destructors are run during PealUnload(). +If the C++ static constructors need to use m68K callbacks, you +can set up the callback pointers before the first PealCall(). + +If you need to force constructors or destructors to run earlier, +use PealCxxConstruct() and PealCxxDestruct(). The constructors +and destructors are run only once, even if you call these functions +multiple times. + +Support for other C++ code has received little testing. +It may or may not work correctly. + + +THUMB COMPATIBILITY + +Peal can be used with Thumb code and interworked ARM/Thumb code. +Thumb code is usually substantially smaller than equivalent ARM code, +but may run more slowly. + +PealCall() may be used with ARM functions or Thumb functions. +Note that PealLookupAddress(myModule, "MyThumbFunction") returns +&MyThumbFunction + 1. This address may be used as a function pointer +in Thumb code or interworking-enabled ARM code. However, this address +may not be passed to PceNativeCall(). Use PealCall() instead. + +PealArmStub() in pealstub.c may be compiled in ARM mode or in Thumb mode: + +If your code is ARM-only: + Compile pealstub.c in ARM mode as usual. + +If your code is Thumb-only: + Compile pealstub.c with `-mthumb -mcallee-super-interworking`. + The latter option is necessary to allow PceNativeCall() to call + PealArmStub() without crashing. + +If your code is mixed ARM and Thumb: + Compile pealstub.c with either `-mno-thumb -mthumb-interwork` (ARM mode) + or `-mthumb -mcallee-super-interworking` (Thumb mode). + + +COMPATIBLITY WITH OTHER COMPILER OPTIONS + +Peal can be used with ARM or Thumb code compiled with `-msingle-pic-base`. +PealArmStub() sets up register R10 as the PIC register. This option is +recommended because it reduces code size and relocation count. + +Peal cannot be used with `-msingle-pic-base -mpic-register=`, +unless the register used is R10. If you need -mpic-register with some +other value, modify PealArmStub() in arm/pealstub.c to use the register +you choose. + +Peal cannot be used with default stack checking, because Peal sets +the stack limit register (R10) as the PIC register. If you need +stack checking, specify a register other than R10 as the stack limit, +or modify PealArmStub() in arm/pealstub.c to use a different PIC +register or no PIC register. + + +POSTLINKER + +The Peal postlinker transforms compiled and linked ARM code into +the relocatable format expected by Peal, and then optionally +packages the code into Palm OS resources. + +peal-postlink expects a single input file that +* is an ELF executable. This is the usual format for ARM code built for Palm. +* is position-independent. Compile with `arm-palmos-gcc -fPIC ...`. +* still contains relocation information. Link with + `arm-palmos-ld --emit-relocs ...` or `arm-palmos-gcc -Wl,--emit-relocs`. + +peal-postlink generates output in two formats: a resource file with +each ELF section in its own resource (`peal-postlink -s ...`), or +an unpackaged ELF relocatable object file (`peal-postlink ...`). + +-s + Generates a PRC-format resource file, with each ELF section in its + own resource. + Each code and data section must be less than 64 KB. See LARGE CODE above. + "resID" is the first resource ID to use. A typical program will occupy + resources resID..resID+9. The default resource type is 'armc'. + This format matches the .ro or .prc formats used by build-prc. + Use PealLoadFromResources(resType, resID) to load this code. + +(without -s) + Generates a single ELF relocatable object file. + Unlike -s, this format has no section size limit. However, if the entire + file is larger than 64 KB, then it will not fit in a Palm OS resource. + In this case, the binary must be split and reassembled in feature memory + or on the heap. See LARGE CODE above. + Use PealLoad(address) to load this code. + +Other options: + +-K + Keeps only symbols listed in the given file, and strips the rest. + By default, all non-static functions and data get a symbol name and + a symbol table entry. This can occupy large amounts of memory. + The `strip` command can remove unwanted entries, but it is also + likely to remove information needed by Peal. The -K option is safer. + Functions and data intended to be used by m68k code must have symbol table + entries. These functions and data should be listed in the keep file. + The symbol "PealArmStub" is required for Peal's operation and will not + be stripped, even if it is not listed in the keep file. + +-o + Sets the output file name. + Typical file name extensions are ".ro" or ".prc" (when using -s), + or ".bin" (when not using -s). + If no -o option is given, peal-postlink overwrites the input file. + +-t + With -s, sets the resource type for generated resources. + This option is silently ignored when not using -s. + +-v + Verbose output. Lists the sections and resources written. + +-V + Prints peal-postlink version, copyright, and lack of warranty. + +peal-postlink silently removes any sections named ".disposn", ".comment", +".got.plt", ".debug*", and ".debu.*". Other sections are copied to the +output file. + +Peal's relocatable image format is similar to an ELF-ARM relocatable +object file, but it does not fully conform to any ELF ABI. + + +API + + PealModule *PealLoad(void *mem) + Loads ARM code and data from mem. + If mem points into a relocatable block, that block must be locked before + calling PealLoad() and must remain locked until after PealUnload(). + Note that PealLoad() may modify *mem. If mem points into a resource + or feature memory block, then mem must point to the beginning of + the block and the memory must be writable with DmWrite(). + Returns NULL if the load fails for any reason. + Warning: if you do not call PealUnload() before your program exits, + your program may crash with a handle lock overflow error when run + more than 16 times. + + PealModule *PealLoadFromResources(DmTypeID type, DmResID baseID) + Loads ARM code and data from resources of the given type, starting + with the given resource ID. + The resources should be numbered sequentially starting with baseID, + one for the ELF header and section list plus one for each ELF section. + This is the output format generated by `peal-postlink -s ...`. + The resources are loaded with DmGetResource(). Some of the + resources are kept open and locked until PealUnload() is called. + Others are released immediately. + The resources must be writable with DmWrite(). + Returns NULL if the load fails for any reason. + Warning: if you do not call PealUnload() before your program exits, + your program may crash with a handle lock overflow error when run + more than 16 times. + + void PealUnload(PealModule *m) + Unloads ARM code and data previously loaded by PealLoad(). + The module must not be used after this call. + Warning: if you do not call PealUnload() before your program exits, + your program may crash with a handle lock overflow error when run + more than 16 times. + + void *PealLookupSymbol(PealModule *m, char *query) + Returns the address of a named ARM function or variable in module m. + Returns NULL if the module contains no such function or variable. + A function can be called by passing this address to PealCall(). + A variable can be read or written by dereferencing this address. + If the named function is a Thumb function, the returned address is + the function's address plus one. This address may be used as a + function pointer in interworking-enabled ARM code. However the + address may not be passed to PceNativeCall. Use PealCall instead. + + uint32_t PealCall(PealModule *m, void *addr, void *arg) + Calls the function at addr in ARM module m, passing it the given arg. + Returns the value returned by that function. + The ARM function PealArmStub() is used to prepare ARM global state. + The called function should take zero or one arguments. + + void PealCxxConstruct(PealModule *m) + Calls C++ constructors if they have not been called already. + By default, Peal calls C++ constructors (if any) during the + first PealCall(). You can force C++ constructors to run earlier + by calling PealCxxConstruct() directly. + Calling PealCxxConstruct() multiple times is harmless. + + void PealCxxDestruct(PealModule *m) + Calls C++ destructors if they have not been called already. + By default, Peal calls C++ destructors (if any) during the + PealUnload(). You can force C++ destructors to run earlier + by calling PealCxxDestruct() directly. + Calling PealCxxDestruct() multiple times is harmless. + + +ALTERNATIVES + +If you don't like Peal, there are several other tools to help provide +a more full-featured ARM environment on Palm OS: + + ARM Relocatable ELF Loader by Hilary Cheng. GPL license. + http://hilary.e-fever.org/arm-elf/ + + elink by Brett Beebe. No license specified. + http://home.comcast.net/~beebeb/palmos/elink.zip + + Roll your own, using Aaron Ardiri's instructions. + http://news.palmos.com/read/messages?id=143901#143901 + http://news.palmos.com/read/messages?id=130117#130117 + + PNOLoader in Metrowerks CodeWarrior 9 for Palm OS. + http://www.metrowerks.com/ + + +LICENSE + +Peal was written by Greg Parker , +using ELF headers by David O'Brien and John Polstra. + +*** + +Copyright (c) 2004-2005 Greg Parker. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*** + +Copyright (c) 2001 David E. O'Brien +Copyright (c) 1996-1998 John D. Polstra. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +*** diff --git a/arm/pealstub.c b/arm/pealstub.c new file mode 100644 index 0000000..d454716 --- /dev/null +++ b/arm/pealstub.c @@ -0,0 +1,85 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#include "pealstub.h" +#include +#include + +// Emulator state for calls back into 68K (set by PealArmStub) +#ifdef __cplusplus +extern "C" { +#endif +const void *gEmulStateP = 0; +Call68KFuncType *gCall68KFuncP = 0; +#ifdef __cplusplus +} +#endif + + +// Must match struct PealArgs in m68k/peal.c +typedef struct { + void *fn; + void *arg; + void *got; +} PealArgs; + + +// reads unaligned and byte-swaps +#define read32(a) \ + ( ((((unsigned char *)(a))[0]) << 24) | \ + ((((unsigned char *)(a))[1]) << 16) | \ + ((((unsigned char *)(a))[2]) << 8) | \ + ((((unsigned char *)(a))[3]) << 0) ) + +// interfacearm attribute means PealArmStub can be called from +// non-interworking ARM code like PceNativeCall if PealArmStub is +// compiled as Thumb code. + +uint32_t PealArmStub(const void *emulStateP, PealArgs *args, Call68KFuncType *call68KFuncP) +{ + uint32_t (*fn)(void *); + void *arg; + register void *got asm("r10"); + const void *oldEmulStateP; + Call68KFuncType *oldCall68KFuncP; + uint32_t result; + + // Unpack args from PealCall() and store GOT in R10 + fn = (uint32_t(*)(void *)) read32(&args->fn); + arg = (void *) read32(&args->arg); + got = (void *) read32(&args->got); + + // Save old PceNativeCall values and set new ones + oldEmulStateP = gEmulStateP; gEmulStateP = emulStateP; + oldCall68KFuncP = gCall68KFuncP; gCall68KFuncP = call68KFuncP; + + // Call the function + result = (*fn)(arg); + + // Restore old PceNativeCall values + gEmulStateP = oldEmulStateP; + gCall68KFuncP = oldCall68KFuncP; + + return result; +} diff --git a/arm/pealstub.h b/arm/pealstub.h new file mode 100644 index 0000000..bdb680e --- /dev/null +++ b/arm/pealstub.h @@ -0,0 +1,41 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#ifndef PEALSTUB_H +#define PEALSTUB_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const void *gEmulStateP; +extern Call68KFuncType *gCall68KFuncP; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/example/Makefile b/example/Makefile new file mode 100644 index 0000000..9660205 --- /dev/null +++ b/example/Makefile @@ -0,0 +1,28 @@ +WARNINGS = -W -Wall -Wpointer-arith + +OPTIMIZATION = -O0 + +all: pealexample.prc + +pealexample.prc: pealexample.def pealexample.o arm/armc.ro pealexample.ro + build-prc -o pealexample.prc pealexample.def pealexample.o pealexample.ro arm/armc.ro + +arm/armc.ro: arm + make -C arm + +pealexample.ro: pealexample.rcp + pilrc -ro pealexample.rcp pealexample.ro + +pealexample.o: m68k.o peal.o + m68k-palmos-gcc m68k.o peal.o -o pealexample.o -lPalmOSGlue + +m68k.o: m68k.c ../m68k/peal.h + m68k-palmos-gcc $(OPTIMIZATION) $(WARNINGS) -I../m68k -c m68k.c -o m68k.o + +peal.o: ../m68k/peal.c ../m68k/peal.h ../m68k/elf.h ../m68k/elf_common.h ../m68k/elf32.h + m68k-palmos-gcc $(OPTIMIZATION) $(WARNINGS) -I../m68k -c ../m68k/peal.c -o peal.o + + +clean: + rm -f *~ *.o *.ro pealexample.o pealexample.prc + make -C arm clean \ No newline at end of file diff --git a/example/arm/Makefile b/example/arm/Makefile new file mode 100644 index 0000000..00806f7 --- /dev/null +++ b/example/arm/Makefile @@ -0,0 +1,15 @@ +WARNINGS = -W -Wall -Wpointer-arith + +OPTIMIZATION = -O0 + +all: armc.ro + +armc.ro: arm.c arm2.c ../../arm/pealstub.c ../../arm/pealstub.h + arm-palmos-gcc -fPIC -Os -march=armv4t -c ../../arm/pealstub.c -o pealstub.o + + arm-palmos-gcc -fPIC -Os -Wl,--split-by-file=60000 -march=armv4t -msingle-pic-base -Wl,--emit-relocs -nostartfiles $(WARNINGS) -I../../arm arm.c arm2.c pealstub.o -o armc03e8.bin + ../../postlink/peal-postlink -v -s 1000 -o armc.ro armc03e8.bin + ../../postlink/peal-postlink -v -o armc.unsplit armc03e8.bin + +clean: + rm -f *.o *~ armc.ro armc03e8.bin diff --git a/example/arm/arm.c b/example/arm/arm.c new file mode 100644 index 0000000..97236b1 --- /dev/null +++ b/example/arm/arm.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include "pealstub.h" + +STANDALONE_CODE_RESOURCE_ID(1000); + + +uint32_t CallCount = 0; +void *Callback_m68k = NULL; + +extern char *ReturnOne(void); +extern char *ReturnTwo(void); +static char * (*fn)(void); + + +// Demonstrate zerofilled non-constant data +uint32_t GetCallCount(void) +{ + CallCount++; + return CallCount; +} + + +// Demonstate function pointers and non-local functions +void SetFunctionPointer(uint32_t which) +{ + CallCount++; + fn = which ? ReturnOne : ReturnTwo; +} + + +// Demonstrate function pointers +char *CallFunctionPointer(void) +{ + CallCount++; + return (*fn)(); +} + + +// Demonstrate 68K calls using globals set by PealArmStub() +uint32_t Call68K(void) +{ + return (*gCall68KFuncP)(gEmulStateP, (unsigned long)Callback_m68k, NULL, 0); +} diff --git a/example/arm/arm2.c b/example/arm/arm2.c new file mode 100644 index 0000000..a237586 --- /dev/null +++ b/example/arm/arm2.c @@ -0,0 +1,14 @@ +// Demonstate constant data +char *ReturnOne(void) +{ + return "One"; +} + + +// Demonstate non-constant initialized data +static char two[] = "Two0"; +char *ReturnTwo(void) +{ + two[3]++; + return two; +} diff --git a/example/m68k.c b/example/m68k.c new file mode 100644 index 0000000..82b3f4f --- /dev/null +++ b/example/m68k.c @@ -0,0 +1,158 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#include +#include +#include +#include "peal.h" + +#define swap32(n) ( ((((unsigned long) (n)) << 24) & 0xFF000000) | \ + ((((unsigned long) (n)) << 8) & 0x00FF0000) | \ + ((((unsigned long) (n)) >> 8) & 0x0000FF00) | \ + ((((unsigned long) (n)) >> 24) & 0x000000FF) ) + + +void print(char *format, ...) +{ + RectangleType r, empty; + char buf[200]; + + va_list args; + va_start(args, format); + StrVPrintF(buf, format, args); + va_end(args); + + r.topLeft.x = 0; + r.topLeft.y = 0; + r.extent.x = 160; + r.extent.y = 160; + WinScrollRectangle(&r, winDown, 12, &empty); + WinEraseRectangle(&empty, 0); + + WinDrawChars(buf, StrLen(buf), 1, 1); +} + +static MemHandle armH = NULL; + +PealModule *load(void) +{ + /* + armH = DmGetResource('armc', 1000); + if (!armH) { + return 0; + } + return PealLoad(MemHandleLock(armH)); + */ + return PealLoadFromResources('armc', 1000); +} + + +void unload(PealModule *m) +{ + PealUnload(m); + /* + MemHandleUnlock(armH); + DmReleaseResource(armH); + */ +} + + +uint32_t callback(void) +{ + return 42; +} + + +void test(PealModule *m) +{ + void *GetCallCount_arm; + void *SetFunctionPointer_arm; + void *CallFunctionPointer_arm; + void *Call68K_arm; + + uint32_t *CallCount_arm; + void **Callback_arm; + uint32_t result; + char *str; + + // Call an ARM function that uses global data + GetCallCount_arm = PealLookupSymbol(m, "GetCallCount"); + + result = PealCall(m, GetCallCount_arm, NULL); + print("CallCount(): %lu", result); + result = PealCall(m, GetCallCount_arm, NULL); + print("CallCount(): %lu", result); + result = PealCall(m, GetCallCount_arm, NULL); + print("CallCount(): %lu", result); + + // Read an ARM variable directly + CallCount_arm = (uint32_t *)PealLookupSymbol(m, "CallCount"); + print("CallCount variable is %lu", swap32(*CallCount_arm)); + + // Call an ARM function that uses function pointers and global data + SetFunctionPointer_arm = PealLookupSymbol(m, "SetFunctionPointer"); + CallFunctionPointer_arm = PealLookupSymbol(m, "CallFunctionPointer"); + + PealCall(m, SetFunctionPointer_arm, (void *)1); + + str = (char *)PealCall(m, CallFunctionPointer_arm, NULL); + print("CallFunctionPointer (fn 1): '%s'", str); + + PealCall(m, SetFunctionPointer_arm, (void *)0); + + str = (char *)PealCall(m, CallFunctionPointer_arm, NULL); + print("CallFunctionPointer (fn 0): '%s'", str); + str = (char *)PealCall(m, CallFunctionPointer_arm, NULL); + print("CallFunctionPointer (fn 0): '%s'", str); + + // Set an ARM variable + Callback_arm = (void **)PealLookupSymbol(m, "Callback_m68k"); + *Callback_arm = (void *)swap32(&callback); + + // Call an ARM function that calls back into m68k + Call68K_arm = PealLookupSymbol(m, "Call68K"); + result = PealCall(m, Call68K_arm, NULL); + print("m68k callback return %lu", result); + + // Read an ARM variable directly + CallCount_arm = PealLookupSymbol(m, "CallCount"); + print("CallCount variable is %lu", swap32(*CallCount_arm)); +} + + +UInt32 PilotMain(UInt16 cmd, void *cmdPBP, UInt16 launchFlags) +{ + PealModule *m; + + // we don't handle search et al. + if (cmd != sysAppLaunchCmdNormalLaunch) return 0; + + m = load(); + test(m); + unload(m); + + print("Quitting in 10 seconds."); + SysTaskDelay(10*SysTicksPerSecond()); + return 0; +} diff --git a/example/pealexample.def b/example/pealexample.def new file mode 100644 index 0000000..0cefe2d --- /dev/null +++ b/example/pealexample.def @@ -0,0 +1,2 @@ +// app name and creator code +application { "PealExample" "????" } diff --git a/example/pealexample.rcp b/example/pealexample.rcp new file mode 100644 index 0000000..204bfcc --- /dev/null +++ b/example/pealexample.rcp @@ -0,0 +1,6 @@ +FORM ID 1000 AT (0 0 160 160) +USABLE +NOSAVEBEHIND +BEGIN + TITLE "PealExample" +END diff --git a/m68k/elf.h b/m68k/elf.h new file mode 100644 index 0000000..4a73d8a --- /dev/null +++ b/m68k/elf.h @@ -0,0 +1,91 @@ +/*- + * Copyright (c) 2001 David E. O'Brien + * Copyright (c) 1996-1997 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/arm/include/elf.h,v 1.4 2003/09/25 01:10:23 peter Exp $ + */ + +#ifndef _MACHINE_ELF_H_ +#define _MACHINE_ELF_H_ 1 + +/* + * EABI ELF definitions for the StrongARM architecture. + * See "ARM ELF", document no. `SWS ESPC 0003 A-08' for details. + */ + +#include "elf32.h" /* Definitions common to all 32 bit architectures. */ + +#define ELF_ARCH EM_ARM + +#define ELF_MACHINE_OK(x) ((x) == EM_ARM) + +/* + * Relocation types. + */ + +#define R_ARM_NONE 0 /* No relocation. */ +#define R_ARM_PC24 1 +#define R_ARM_ABS32 2 +#define R_ARM_REL32 3 +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 +#define R_ARM_ABS12 6 +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_COPY 20 /* Copy data from shared object. */ +#define R_ARM_GLOB_DAT 21 /* Set GOT entry to data address. */ +#define R_ARM_JUMP_SLOT 22 /* Set GOT entry to code address. */ +#define R_ARM_RELATIVE 23 /* Add load address of shared object. */ +#define R_ARM_GOTOFF 24 /* Add GOT-relative symbol address. */ +#define R_ARM_GOTPC 25 /* Add PC-relative GOT table address. */ +#define R_ARM_GOT32 26 /* Add PC-relative GOT offset. */ +#define R_ARM_PLT32 27 /* Add PC-relative PLT offset. */ +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS32 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 + +#define R_ARM_COUNT 33 /* Count of defined relocation types. */ + + +/* Define "machine" characteristics */ +#define ELF_TARG_CLASS ELFCLASS32 +#define ELF_TARG_DATA ELFDATA2LSB +#define ELF_TARG_MACH EM_ARM +#define ELF_TARG_VER 1 + +#endif /* !_MACHINE_ELF_H_ */ diff --git a/m68k/elf32.h b/m68k/elf32.h new file mode 100644 index 0000000..c74f643 --- /dev/null +++ b/m68k/elf32.h @@ -0,0 +1,157 @@ +/*- + * Copyright (c) 1996-1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/sys/elf32.h,v 1.8 2002/05/30 08:32:18 dfr Exp $ + */ + +#ifndef _SYS_ELF32_H_ +#define _SYS_ELF32_H_ 1 + +#include +#include "elf_common.h" + +/* + * ELF definitions common to all 32-bit architectures. + */ + +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; +typedef uint32_t Elf32_Size; +typedef Elf32_Off Elf32_Hashelt; + +/* + * ELF header. + */ + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* File identification. */ + Elf32_Half e_type; /* File type. */ + Elf32_Half e_machine; /* Machine architecture. */ + Elf32_Word e_version; /* ELF format version. */ + Elf32_Addr e_entry; /* Entry point. */ + Elf32_Off e_phoff; /* Program header file offset. */ + Elf32_Off e_shoff; /* Section header file offset. */ + Elf32_Word e_flags; /* Architecture-specific flags. */ + Elf32_Half e_ehsize; /* Size of ELF header in bytes. */ + Elf32_Half e_phentsize; /* Size of program header entry. */ + Elf32_Half e_phnum; /* Number of program header entries. */ + Elf32_Half e_shentsize; /* Size of section header entry. */ + Elf32_Half e_shnum; /* Number of section header entries. */ + Elf32_Half e_shstrndx; /* Section name strings section. */ +} Elf32_Ehdr; + +/* + * Section header. + */ + +typedef struct { + Elf32_Word sh_name; /* Section name (index into the + section header string table). */ + Elf32_Word sh_type; /* Section type. */ + Elf32_Word sh_flags; /* Section flags. */ + Elf32_Addr sh_addr; /* Address in memory image. */ + Elf32_Off sh_offset; /* Offset in file. */ + Elf32_Size sh_size; /* Size in bytes. */ + Elf32_Word sh_link; /* Index of a related section. */ + Elf32_Word sh_info; /* Depends on section type. */ + Elf32_Size sh_addralign; /* Alignment in bytes. */ + Elf32_Size sh_entsize; /* Size of each entry in section. */ +} Elf32_Shdr; + +/* + * Program header. + */ + +typedef struct { + Elf32_Word p_type; /* Entry type. */ + Elf32_Off p_offset; /* File offset of contents. */ + Elf32_Addr p_vaddr; /* Virtual address in memory image. */ + Elf32_Addr p_paddr; /* Physical address (not used). */ + Elf32_Size p_filesz; /* Size of contents in file. */ + Elf32_Size p_memsz; /* Size of contents in memory. */ + Elf32_Word p_flags; /* Access permission flags. */ + Elf32_Size p_align; /* Alignment in memory and file. */ +} Elf32_Phdr; + +/* + * Dynamic structure. The ".dynamic" section contains an array of them. + */ + +typedef struct { + Elf32_Sword d_tag; /* Entry type. */ + union { + Elf32_Size d_val; /* Integer value. */ + Elf32_Addr d_ptr; /* Address value. */ + } d_un; +} Elf32_Dyn; + +/* + * Relocation entries. + */ + +/* Relocations that don't need an addend field. */ +typedef struct { + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Relocation type and symbol index. */ +} Elf32_Rel; + +/* Relocations that need an addend field. */ +typedef struct { + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Relocation type and symbol index. */ + Elf32_Sword r_addend; /* Addend. */ +} Elf32_Rela; + +/* Macros for accessing the fields of r_info. */ +#define ELF32_R_SYM(info) ((info) >> 8) +#define ELF32_R_TYPE(info) ((unsigned char)(info)) + +/* Macro for constructing r_info from field values. */ +#define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type)) + +/* + * Symbol table entries. + */ + +typedef struct { + Elf32_Word st_name; /* String table index of name. */ + Elf32_Addr st_value; /* Symbol value. */ + Elf32_Size st_size; /* Size of associated object. */ + unsigned char st_info; /* Type and binding information. */ + unsigned char st_other; /* Reserved (not used). */ + Elf32_Half st_shndx; /* Section index of symbol. */ +} Elf32_Sym; + +/* Macros for accessing the fields of st_info. */ +#define ELF32_ST_BIND(info) ((info) >> 4) +#define ELF32_ST_TYPE(info) ((info) & 0xf) + +/* Macro for constructing st_info from field values. */ +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +#endif /* !_SYS_ELF32_H_ */ diff --git a/m68k/elf_common.h b/m68k/elf_common.h new file mode 100644 index 0000000..ee3a904 --- /dev/null +++ b/m68k/elf_common.h @@ -0,0 +1,299 @@ +/*- + * Copyright (c) 1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/sys/elf_common.h,v 1.14 2003/06/18 16:38:22 kan Exp $ + */ + +#ifndef _SYS_ELF_COMMON_H_ +#define _SYS_ELF_COMMON_H_ 1 + +/* + * ELF definitions that are independent of architecture or word size. + */ + +/* + * Note header. The ".note" section contains an array of notes. Each + * begins with this header, aligned to a word boundary. Immediately + * following the note header is n_namesz bytes of name, padded to the + * next word boundary. Then comes n_descsz bytes of descriptor, again + * padded to a word boundary. The values of n_namesz and n_descsz do + * not include the padding. + */ + +typedef struct { + uint32_t n_namesz; /* Length of name. */ + uint32_t n_descsz; /* Length of descriptor. */ + uint32_t n_type; /* Type of this note. */ +} Elf_Note; + +/* Indexes into the e_ident array. Keep synced with + http://www.sco.com/developer/gabi/ch4.eheader.html */ +#define EI_MAG0 0 /* Magic number, byte 0. */ +#define EI_MAG1 1 /* Magic number, byte 1. */ +#define EI_MAG2 2 /* Magic number, byte 2. */ +#define EI_MAG3 3 /* Magic number, byte 3. */ +#define EI_CLASS 4 /* Class of machine. */ +#define EI_DATA 5 /* Data format. */ +#define EI_VERSION 6 /* ELF format version. */ +#define EI_OSABI 7 /* Operating system / ABI identification */ +#define EI_ABIVERSION 8 /* ABI version */ +#define OLD_EI_BRAND 8 /* Start of architecture identification. */ +#define EI_PAD 9 /* Start of padding (per SVR4 ABI). */ +#define EI_NIDENT 16 /* Size of e_ident array. */ + +/* Values for the magic number bytes. */ +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" /* magic string */ +#define SELFMAG 4 /* magic string size */ + +/* Values for e_ident[EI_VERSION] and e_version. */ +#define EV_NONE 0 +#define EV_CURRENT 1 + +/* Values for e_ident[EI_CLASS]. */ +#define ELFCLASSNONE 0 /* Unknown class. */ +#define ELFCLASS32 1 /* 32-bit architecture. */ +#define ELFCLASS64 2 /* 64-bit architecture. */ + +/* Values for e_ident[EI_DATA]. */ +#define ELFDATANONE 0 /* Unknown data format. */ +#define ELFDATA2LSB 1 /* 2's complement little-endian. */ +#define ELFDATA2MSB 2 /* 2's complement big-endian. */ + +/* Values for e_ident[EI_OSABI]. */ +#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ +#define ELFOSABI_NONE ELFOSABI_SYSV /* symbol used in old spec */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_MONTEREY 7 /* Monterey */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* Values for e_type. */ +#define ET_NONE 0 /* Unknown type. */ +#define ET_REL 1 /* Relocatable. */ +#define ET_EXEC 2 /* Executable. */ +#define ET_DYN 3 /* Shared object. */ +#define ET_CORE 4 /* Core file. */ + +/* Values for e_machine. */ +#define EM_NONE 0 /* Unknown machine. */ +#define EM_M32 1 /* AT&T WE32100. */ +#define EM_SPARC 2 /* Sun SPARC. */ +#define EM_386 3 /* Intel i386. */ +#define EM_68K 4 /* Motorola 68000. */ +#define EM_88K 5 /* Motorola 88000. */ +#define EM_486 6 /* Intel i486. */ +#define EM_860 7 /* Intel i860. */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ + +/* Extensions. This list is not complete. */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ /* Depreciated */ +#define EM_PARISC 15 /* HPPA */ +#define EM_SPARC32PLUS 18 /* SPARC v8plus */ +#define EM_PPC 20 /* PowerPC 32-bit */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_ARM 40 /* ARM */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_IA_64 50 /* Intel IA-46 Processor */ +#define EM_X86_64 62 /* Advanced Micro Devices x86-64 */ +#define EM_ALPHA 0x9026 /* Alpha (written in the absence of an ABI */ + +/* Special section indexes. */ +#define SHN_UNDEF 0 /* Undefined, missing, irrelevant. */ +#define SHN_LORESERVE 0xff00 /* First of reserved range. */ +#define SHN_LOPROC 0xff00 /* First processor-specific. */ +#define SHN_HIPROC 0xff1f /* Last processor-specific. */ +#define SHN_ABS 0xfff1 /* Absolute values. */ +#define SHN_COMMON 0xfff2 /* Common data. */ +#define SHN_HIRESERVE 0xffff /* Last of reserved range. */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends */ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relocation section - no addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_NUM 12 /* number of section types */ +#define SHT_LOOS 0x60000000 /* First of OS specific semantics */ +#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Flags for sh_flags. */ +#define SHF_WRITE 0x1 /* Section contains writable data. */ +#define SHF_ALLOC 0x2 /* Section occupies memory. */ +#define SHF_EXECINSTR 0x4 /* Section contains instructions. */ +#define SHF_TLS 0x400 /* Section contains TLS data. */ +#define SHF_MASKPROC 0xf0000000 /* Reserved for processor-specific. */ + +/* Values for p_type. */ +#define PT_NULL 0 /* Unused entry. */ +#define PT_LOAD 1 /* Loadable segment. */ +#define PT_DYNAMIC 2 /* Dynamic linking information segment. */ +#define PT_INTERP 3 /* Pathname of interpreter. */ +#define PT_NOTE 4 /* Auxiliary information. */ +#define PT_SHLIB 5 /* Reserved (not used). */ +#define PT_PHDR 6 /* Location of program header itself. */ +#define PT_TLS 7 /* Thread local storage segment */ + +#define PT_COUNT 8 /* Number of defined p_type values. */ + +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 /* First processor-specific type. */ +#define PT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +/* Values for p_flags. */ +#define PF_X 0x1 /* Executable. */ +#define PF_W 0x2 /* Writable. */ +#define PF_R 0x4 /* Readable. */ + +/* Values for d_tag. */ +#define DT_NULL 0 /* Terminating entry. */ +#define DT_NEEDED 1 /* String table offset of a needed shared + library. */ +#define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */ +#define DT_PLTGOT 3 /* Processor-dependent address. */ +#define DT_HASH 4 /* Address of symbol hash table. */ +#define DT_STRTAB 5 /* Address of string table. */ +#define DT_SYMTAB 6 /* Address of symbol table. */ +#define DT_RELA 7 /* Address of ElfNN_Rela relocations. */ +#define DT_RELASZ 8 /* Total size of ElfNN_Rela relocations. */ +#define DT_RELAENT 9 /* Size of each ElfNN_Rela relocation entry. */ +#define DT_STRSZ 10 /* Size of string table. */ +#define DT_SYMENT 11 /* Size of each symbol table entry. */ +#define DT_INIT 12 /* Address of initialization function. */ +#define DT_FINI 13 /* Address of finalization function. */ +#define DT_SONAME 14 /* String table offset of shared object + name. */ +#define DT_RPATH 15 /* String table offset of library path. [sup] */ +#define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */ +#define DT_REL 17 /* Address of ElfNN_Rel relocations. */ +#define DT_RELSZ 18 /* Total size of ElfNN_Rel relocations. */ +#define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */ +#define DT_PLTREL 20 /* Type of relocation used for PLT. */ +#define DT_DEBUG 21 /* Reserved (not used). */ +#define DT_TEXTREL 22 /* Indicates there may be relocations in + non-writable segments. [sup] */ +#define DT_JMPREL 23 /* Address of PLT relocations. */ +#define DT_BIND_NOW 24 /* [sup] */ +#define DT_INIT_ARRAY 25 /* Address of the array of pointers to + initialization functions */ +#define DT_FINI_ARRAY 26 /* Address of the array of pointers to + termination functions */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of the array of + initialization functions. */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of the array of + terminationfunctions. */ +#define DT_RUNPATH 29 /* String table offset of a null-terminated + library search path string. */ +#define DT_FLAGS 30 /* Object specific flag values. */ +#define DT_ENCODING 32 /* Values greater than or equal to DT_ENCODING + and less than DT_LOOS follow the rules for + the interpretation of the d_un union + as follows: even == 'd_ptr', even == 'd_val' + or none */ +#define DT_PREINIT_ARRAY 32 /* Address of the array of pointers to + pre-initialization functions. */ +#define DT_PREINIT_ARRAYSZ 33 /* Size in bytes of the array of + pre-initialization functions. */ + +#define DT_COUNT 33 /* Number of defined d_tag values. */ + +#define DT_LOOS 0x6000000d /* First OS-specific */ +#define DT_HIOS 0x6fff0000 /* Last OS-specific */ +#define DT_LOPROC 0x70000000 /* First processor-specific type. */ +#define DT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +/* Values for DT_FLAGS */ +#define DF_ORIGIN 0x0001 /* Indicates that the object being loaded may + make reference to the $ORIGIN substitution + string */ +#define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */ +#define DF_TEXTREL 0x0004 /* Indicates there may be relocations in + non-writable segments. */ +#define DF_BIND_NOW 0x0008 /* Indicates that the dynamic linker should + process all relocations for the object + containing this entry before transferring + control to the program. */ +#define DF_STATIC_TLS 0x0010 /* Indicates that the shared object or + executable contains code using a static + thread-local storage scheme. */ + +/* Values for n_type. Used in core files. */ +#define NT_PRSTATUS 1 /* Process status. */ +#define NT_FPREGSET 2 /* Floating point registers. */ +#define NT_PRPSINFO 3 /* Process state info. */ + +/* Symbol Binding - ELFNN_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific symbol bindings */ + +/* Symbol type - ELFNN_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* Unspecified type. */ +#define STT_OBJECT 1 /* Data object. */ +#define STT_FUNC 2 /* Function. */ +#define STT_SECTION 3 /* Section. */ +#define STT_FILE 4 /* Source file. */ +#define STT_TLS 6 /* TLS object. */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific symbol types */ + +/* Special symbol table indexes. */ +#define STN_UNDEF 0 /* Undefined symbol index. */ + +#endif /* !_SYS_ELF_COMMON_H_ */ diff --git a/m68k/peal.c b/m68k/peal.c new file mode 100644 index 0000000..bf7fcff --- /dev/null +++ b/m68k/peal.c @@ -0,0 +1,905 @@ +/********** + * Copyright (c) 2004-2005 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#include +#include +#include +#include +#include + +#include "peal.h" + +#include "elf.h" + + +typedef struct { + uint32_t vm_addr; + uint32_t block; + Boolean is_resource; + Boolean is_heap; +} SectionInfo; + +struct PealModule { + Elf32_Ehdr *ehdr; + + uint32_t symcount; + Elf32_Sym *syms; // real address of .symtab section + char *strings; // real address of .strtab section + uintptr_t got; // real address of .got section + + uintptr_t rw_block; // heap block containing rw_start (unaligned) + uintptr_t rw_start; // real address of all r/w memory (aligned) + SectionInfo *sinfo; // real addresses of each section + + uintptr_t stub; // PealArmStub() + + Boolean cxx_constructed; + Boolean cxx_destructed; +}; + + +// Must match struct PealArgs in arm/pealstub.c +typedef struct { + void *fn; + void *arg; + void *got; +} PealArgs; + + +static inline uint32_t swap32(uint32_t v) +{ + return ( + ((v & 0x000000ff) << 24) | + ((v & 0x0000ff00) << 8) | + ((v & 0x00ff0000) >> 8) | + ((v & 0xff000000) >> 24) + ); +} + + +static inline uint16_t swap16(uint16_t v) +{ + return ( + ((v & 0x00ff) << 8) | + ((v & 0xff00) >> 8) + ); +} + + +static inline void swap_ehdr(Elf32_Ehdr *ehdr) +{ + ehdr->e_type = swap16(ehdr->e_type); + ehdr->e_machine = swap16(ehdr->e_machine); + ehdr->e_version = swap32(ehdr->e_version); + ehdr->e_entry = swap32(ehdr->e_entry); + ehdr->e_phoff = swap32(ehdr->e_phoff); + ehdr->e_shoff = swap32(ehdr->e_shoff); + ehdr->e_flags = swap32(ehdr->e_flags); + ehdr->e_ehsize = swap16(ehdr->e_ehsize); + ehdr->e_phentsize = swap16(ehdr->e_phentsize); + ehdr->e_phnum = swap16(ehdr->e_phnum); + ehdr->e_shentsize = swap16(ehdr->e_shentsize); + ehdr->e_shnum = swap16(ehdr->e_shnum); + ehdr->e_shstrndx = swap16(ehdr->e_shstrndx); +} + + +static uint16_t peek16(uintptr_t block, uintptr_t dst) +{ + block = block; + return swap16(*(uint16_t *)dst); +} + +static uint32_t peek32(uintptr_t block, uintptr_t dst) +{ + block = block; + return swap32(*(uint32_t *)dst); +} + +static void poke16(uintptr_t block, uintptr_t dst, uint16_t value) +{ + ptrdiff_t offset = dst - block; + value = swap16(value); + if (0 == DmWriteCheck((void *)block, offset, sizeof(value))) { + DmWrite((void *)block, offset, &value, sizeof(value)); + } else { + *(uint16_t *)dst = value; + } +} + +static void poke32(uintptr_t block, uintptr_t dst, uint32_t value) +{ + ptrdiff_t offset = dst - block; + value = swap32(value); + if (0 == DmWriteCheck((void *)block, offset, sizeof(value))) { + DmWrite((void *)block, offset, &value, sizeof(value)); + } else { + *(uint32_t *)dst = value; + } +} + + +static Elf32_Shdr *section_for_index(Elf32_Ehdr *ehdr, uint16_t index) +{ + Elf32_Shdr *shdr; + if (index >= swap16(ehdr->e_shnum)) return NULL; + shdr = (Elf32_Shdr *)(((uint8_t *)ehdr)+swap32(ehdr->e_shoff)); + return shdr+index; +} + + +static char *section_name(PealModule *m, Elf32_Shdr *shdr) +{ + // NOT m->strings! + char *strings = (char *)m->sinfo[swap16(m->ehdr->e_shstrndx)].vm_addr; + return strings + swap32(shdr->sh_name); +} + + +// ELF file behaves like a .o, so st_value is an in-section offset +#define thumb 1 +static uintptr_t symbol_address(PealModule *m, Elf32_Sym *sym, int interwork) +{ + int index = swap16(sym->st_shndx); + uintptr_t address = + (uintptr_t)(m->sinfo[index].vm_addr + swap32(sym->st_value)); + if (interwork && ELF32_ST_TYPE(sym->st_info) == STT_LOPROC) { + // symbol is a pointer to a Thumb function - use interworkable address + address++; + } + return address; +} + + +static char *symbol_name(PealModule *m, Elf32_Sym *sym) +{ + return m->strings + swap32(sym->st_name); +} + + +static Elf32_Sym *symbol_lookup(PealModule *m, char *query) +{ + uint32_t i; + if (!m->syms || !m->strings || !query) return NULL; // sorry + + for (i = 0; i < m->symcount; i++) { + Elf32_Sym *sym = m->syms+i; + char *name = symbol_name(m, sym); + if (0 == StrCompareAscii(name, query)) { + return sym; + } + } + + return NULL; // no symbol - sorry +} + + +/* + thunks from Thumb code: + BL: thunk is Thumb, jumps to Thumb + BLX: thunk is ARM, jumps to ARM + + thunks from ARM code: + Bcc: thunk is ARM, jumps to ARM + BLcc: thunk is ARM, jumps to ARM + BLX: thunk is Thumb, jumps to Thumb +*/ + +// 1: thumb thunk +// 0: arm thunk +// -1: bad src +static int choose_thunk(uintptr_t src, Boolean srcIsThumb) +{ + if (srcIsThumb) { + uint16_t insn1 = swap16(*(uint16_t *)src); + uint16_t insn2 = swap16(*(uint16_t *)(src+2)); + uint16_t opcode1 = insn1 >> 11; + uint16_t opcode2 = insn2 >> 11; + if (opcode1 == 0x001e && opcode2 == 0x001f) { + // BL: Thumb->Thumb branch, use Thumb thunk + return thumb; + } else if (opcode1 == 0x001e && opcode2 == 0x001d) { + // BLX: Thumb->ARM branch, use ARM thunk + return 0; + } else { + // unknown instruction + return -1; + } + } else { + uint32_t insn = swap32(*(uint32_t *)src); + uint32_t cond = (insn & 0xf0000000) >> 28; + uint32_t opcode = (insn & 0x0e000000) >> 25; + if (opcode == 0x05) { + if (cond == 0x0f) { + // BLX: ARM->Thumb branch, use Thumb thunk + return thumb; + } else { + // Bcc, BLcc: ARM->ARM branch, use ARM thunk + return 0; + } + } else { + // unknown instruction + return -1; + } + } +} + + +/* + Thumb thunk + * 16 bytes total + * must be 4-byte aligned with leading NOP to handle ARM BLX + * data value is dst+1 so BX stays in Thumb mode + * for LDR, the PC is already 4 bytes ahead, and the immediate must + be 4-byte aligned. + + code (little-endian): + 00 46C0 NOP + 02 B401 PUSH r0 + 04 4801 LDR r0, [PC, #4] + 06 4684 MOV r12, r0 + 08 BC01 POP r0 + 0a 4760 BX r12 + data: + 0c 4-byte dst+1 (needs +1 so BX stays in Thumb mode) +*/ + +/* + ARM thunk + * 8 bytes total + * for LDR, the PC is already 8 bytes ahead + * `LDR PC, ...` on ARMv5T will switch to Thumb mode if dest bit 0 is set, + but that should never happen here. + + code (big-endian): + 00 E51FF004 LDR PC, [PC, #-4] + data: + 04 4-byte dst +*/ + + +typedef struct { + uintptr_t thunk; + uintptr_t dst; +} thunk_desc_t; + +// thunkList[0] is ARM, thunkList[1] is Thumb +static thunk_desc_t *thunkList[2] = {NULL, NULL}; +static unsigned int thunksUsed[2] = {0, 0}; +static unsigned int thunksAllocated[2] = {0, 0}; + + +// arch 1 == Thumb, arch 0 == ARM +static thunk_desc_t *find_thunk_desc(uintptr_t dst, int arch) +{ + thunk_desc_t *desc; + unsigned int i; + + // Search for existing thunk. + for (i = 0; i < thunksUsed[arch]; i++) { + desc = &thunkList[arch][i]; + if (desc->dst == dst) return desc; + } + + // No match. Make new thunk descriptor. + if (thunksUsed[arch] == thunksAllocated[arch]) { + thunk_desc_t *newList; + thunksAllocated[arch] = thunksAllocated[arch] * 2 + 8; + newList = MemPtrNew(thunksAllocated[arch] * sizeof(thunk_desc_t)); + if (!newList) return NULL; + MemSet(newList, thunksAllocated[arch] * sizeof(thunk_desc_t), 0); + if (thunkList[arch]) { + MemMove(newList, thunkList[arch], + thunksUsed[arch] * sizeof(thunk_desc_t)); + MemPtrFree(thunkList[arch]); + } + thunkList[arch] = newList; + } + desc = &thunkList[arch][thunksUsed[arch]++]; + desc->thunk = 0; + desc->dst = dst; + return desc; +} + + +static void free_thunk_descs(void) +{ + if (thunkList[0]) MemPtrFree(thunkList[0]); + if (thunkList[1]) MemPtrFree(thunkList[1]); + thunkList[0] = thunkList[1] = NULL; + thunksUsed[0] = thunksUsed[1] = 0; + thunksAllocated[0] = thunksAllocated[1] = 0; +} + + +static Boolean insn_is_bx(uint16_t insn) +{ + uint16_t opcode = insn >> 7; // keep prefix+opcode+H1; discard H2+regs + + return (opcode == 0x8e); // 010001 11 0 x xxx xxx +} + + +static uintptr_t generate_thunk(uintptr_t *thunks, + uintptr_t src_block, uintptr_t src, + uintptr_t dst, int srcIsThumb) +{ + int thunkIsThumb; + thunk_desc_t *desc; + + // Examine the instruction at *src to choose which thunk type we need. + thunkIsThumb = choose_thunk(src, srcIsThumb); + if (thunkIsThumb < 0) return 0; + + // Look for an existing thunk with the same dst and instruction set, + // and make a new one if necessary + desc = find_thunk_desc(dst, thunkIsThumb); + if (!desc) return 0; // out of memory + if (desc->thunk == 0) { + // New thunk. + if (thunkIsThumb) { + uint16_t target_insn = swap16(*(uint16_t *)dst); + desc->thunk = (*thunks -= 16); + if (insn_is_bx(target_insn)) { + // Branch target insn at dst is another bx (e.g. call_via_rX + // glue). Simply copy that instruction into the stub. + // This is necessary for correctness - the Thumb thunk + // interferes with call_via_ip - and also runs faster. + // fixme need to handle BLX too? + poke16(src_block, desc->thunk + 0, target_insn); + } else { + // Normal Thumb thunk. + poke16(src_block, desc->thunk + 0, 0x46C0); // NOP + poke16(src_block, desc->thunk + 2, 0xB401); // PUSH r0 + poke16(src_block, desc->thunk + 4, 0x4801); // LDR r0,[PC,#4] + poke16(src_block, desc->thunk + 6, 0x4684); // MOV r12, r0 + poke16(src_block, desc->thunk + 8, 0xBC01); // POP r0 + poke16(src_block, desc->thunk + 10, 0x4760); // BX r12 + poke32(src_block, desc->thunk + 12, dst | 1); + } + } else { + desc->thunk = (*thunks -= 8); + poke32(src_block, desc->thunk + 0, 0xE51FF004); // LDR PC, [PC,#-4] + poke32(src_block, desc->thunk + 4, dst); + } + } + return desc->thunk; +} + + +static PealModule *allocate(Elf32_Ehdr *ehdr) +{ + size_t size; + PealModule *m = MemPtrNew(sizeof(*m)); + if (!m) return NULL; + + // fixme sanity-check ehdr + + MemSet(m, sizeof(*m), 0); + m->ehdr = ehdr; + size = sizeof(SectionInfo) * swap16(m->ehdr->e_shnum); + m->sinfo = MemPtrNew(size); + MemSet(m->sinfo, size, 0); + return m; +} + + +static void cleanup(PealModule *m) +{ + free_thunk_descs(); + + if (m) { + if (m->sinfo) { + unsigned int i, count = swap16(m->ehdr->e_shnum); + for (i = 0; i < count; i++) { + if (m->sinfo[i].is_resource) { + MemHandle rsrcH = + MemPtrRecoverHandle((void *)m->sinfo[i].block); + MemHandleUnlock(rsrcH); + DmReleaseResource(rsrcH); + } else if (m->sinfo[i].is_heap) { + MemPtrFree((void *)m->sinfo[i].block); + } + } + MemPtrFree(m->sinfo); + } + if (m->rw_block) MemPtrFree((void *)m->rw_block); + MemPtrFree(m); + } +} + + +static Boolean load(PealModule *m) +{ + Elf32_Shdr *shdr; + Elf32_Sym *stub_sym; + uintptr_t rw_sh_addr; + uintptr_t rw_sh_end; + ptrdiff_t rw_slide; + unsigned int i; + uint32_t max_align = 1; + + // find extent of r/w memory + rw_sh_addr = 0xffffffff; + rw_sh_end = 0; + for (i = 0; (shdr = section_for_index(m->ehdr, i)); i++) { + uint32_t sh_flags = swap32(shdr->sh_flags); + uint32_t sh_addr = swap32(shdr->sh_addr); + uint32_t sh_size = swap32(shdr->sh_size); + uint32_t sh_type = swap32(shdr->sh_type); + uint32_t sh_addralign = swap32(shdr->sh_addralign); + + if ((sh_flags & SHF_ALLOC) && + (sh_type == SHT_PROGBITS || sh_type == SHT_NOBITS)) + { + if ((sh_flags & SHF_WRITE) && sh_addr < rw_sh_addr) { + rw_sh_addr = sh_addr; + } + if ((sh_flags & SHF_WRITE) && sh_addr + sh_size > rw_sh_end) { + rw_sh_end = sh_addr + sh_size; + } + if (sh_addralign > max_align) { + max_align = sh_addralign; + } + } + } + + + // allocate r/w memory + if (rw_sh_addr == 0xffffffff || rw_sh_addr == rw_sh_end) { + m->rw_block = 0; + m->rw_start = 0; + rw_slide = 0; + } else { + // add leading pad to fix alignment in case first rw section + // is less aligned than other rw sections. + rw_sh_addr -= rw_sh_addr % max_align; + + // add leading pad to heap block in case max_align is + // more aligned than MemGluePtrNew's result. + m->rw_block = (uintptr_t)MemGluePtrNew(rw_sh_end - rw_sh_addr + max_align); + if (!m->rw_block) return false; + m->rw_start = m->rw_block + (max_align - m->rw_block % max_align); + if (m->rw_start % max_align) return false; + + rw_slide = m->rw_start - rw_sh_addr; + } + + + // populate r/w memory + for (i = 0; (shdr = section_for_index(m->ehdr, i)); i++) { + uint32_t sh_flags = swap32(shdr->sh_flags); + uint32_t sh_addr = swap32(shdr->sh_addr); + uint32_t sh_size = swap32(shdr->sh_size); + uint32_t sh_type = swap32(shdr->sh_type); + void *vm_addr = (void *)(sh_addr + rw_slide); + + if ((sh_flags & SHF_ALLOC) && (sh_flags & SHF_WRITE) && + (sh_type == SHT_NOBITS || sh_type == SHT_PROGBITS)) + { + if (sh_type == SHT_NOBITS) { + MemSet(vm_addr, sh_size, 0); // .bss section + } else { + MemMove(vm_addr, (void *)m->sinfo[i].vm_addr, sh_size); + } + + // use r/w location instead of r/o location from now on + // If this section was in a large resource, block is a + // temporary heap buffer that is now freed. + // fixme large temporary buffers suck + if (m->sinfo[i].is_resource) { + MemHandle rsrcH = + MemPtrRecoverHandle((void *)m->sinfo[i].block); + MemHandleUnlock(rsrcH); + DmReleaseResource(rsrcH); + } else if (m->sinfo[i].is_heap) { + MemPtrFree((void *)m->sinfo[i].block); + } + m->sinfo[i].block = m->rw_block; + m->sinfo[i].vm_addr = (uintptr_t)vm_addr; + m->sinfo[i].is_resource = false; + m->sinfo[i].is_heap = false; + } + } + + + // find symtab and string sections (both unique) + m->syms = NULL; + m->symcount = 0; + m->strings = 0; + for (i = 0; (shdr = section_for_index(m->ehdr, i)); i++) { + if (swap32(shdr->sh_type) == SHT_SYMTAB) { + m->syms = (Elf32_Sym *)m->sinfo[i].vm_addr; + m->symcount = swap32(shdr->sh_size) / sizeof(Elf32_Sym); + } + if (swap32(shdr->sh_type) == SHT_STRTAB) { + m->strings = (char *)m->sinfo[i].vm_addr; + } + } + + + // find GOT using section named .got + // This must be done AFTER the symtab, strtab, and slides are available + // This must be done BEFORE relocations are performed + m->got = 0; + for (i = 0; (shdr = section_for_index(m->ehdr, i)); i++) { + const char *name = section_name(m, shdr); + if (0 == StrNCompareAscii(name, ".got", 5)) { + m->got = m->sinfo[i].vm_addr; + break; + } + } + + + // perform relocations + // Don't use Thumb interworkable addresses for any relocation. + // All of these symbols should be section symbols, and any + // interwork mangling should have been done by peal-postlink. + for (i = 0; (shdr = section_for_index(m->ehdr, i)); i++) { + uint32_t sh_size = swap32(shdr->sh_size); + uint32_t sh_type = swap32(shdr->sh_type); + Elf32_Rela *rel, *relend; + uint32_t dst_base; + uintptr_t dst_block; + size_t dst_size; + uint32_t dst_index; + uintptr_t dst_thunks; + + if (sh_type != SHT_RELA) continue; + + free_thunk_descs(); + + rel = (Elf32_Rela *)m->sinfo[i].vm_addr; + relend = rel + sh_size / sizeof(Elf32_Rela); + + dst_index = swap32(shdr->sh_info); + dst_base = m->sinfo[dst_index].vm_addr; + dst_block = m->sinfo[dst_index].block; + dst_size = swap32(section_for_index(m->ehdr, dst_index)->sh_size); + dst_thunks = dst_base + dst_size; // assume postlinker aligned this + + for ( ; rel < relend; rel++) { + uint32_t dst_offset; + uint32_t sym_index; + Elf32_Sym *dst_sym; + uintptr_t dst; + uint32_t addend; + + dst_offset = swap32(rel->r_offset); + sym_index = ELF32_R_SYM(swap32(rel->r_info)); + dst_sym = m->syms + sym_index; + addend = swap32(rel->r_addend); + + // *dst is ARM-swapped, and may be in storage memory. + // Use poke32() to change it. + dst = dst_base + dst_offset; + + switch (ELF32_R_TYPE(swap32(rel->r_info))) { + case R_ARM_PC24: { + // *dst[0-23] = ((symbol + addend - dst) - 8) / 4 + // value must be SIGNED! + uintptr_t symbol = symbol_address(m, dst_sym, 0); + int32_t value = symbol + addend - (uintptr_t)dst; + if (value % 4) return false; + value = (value - 8) / 4; + + if (value != ((value << 8) >> 8)) { + // Relocation no longer fits in 24 bits. Use a thunk. + uintptr_t thunk = + generate_thunk(&dst_thunks, dst_block, dst, + symbol + addend, 0); + if (thunk == 0) return false; + + // Re-aim value at the thunk. + value = thunk - (uintptr_t)dst; + if (value % 4) return false; + value = (value - 8) / 4; + if (value != ((value << 8) >> 8)) return false; + } + + poke32(dst_block, dst, + (value & 0x00ffffff) | + (peek32(dst_block, dst) & 0xff000000)); + break; + } + case R_ARM_THM_PC22: { + // *(dst+0)[0-10] = (((symbol + addend - dst) - 4) / 2)[11-21] + // *(dst+2)[0-10] = (((symbol + addend - dst) - 4) / 2)[0-10] + // value must be SIGNED! + uintptr_t symbol = symbol_address(m, dst_sym, 0); + int32_t value = symbol + addend - (uintptr_t)dst; + if (value % 2) return false; + value = (value - 4) / 2; + + if (value != ((value << 10) >> 10)) { + // Relocation no longer fits in 22 bits. Use a thunk. + uintptr_t thunk = + generate_thunk(&dst_thunks, dst_block, dst, + (symbol+addend) & 0xfffffffe, thumb); + if (thunk == 0) return false; + + // Re-aim value at the thunk. + value = thunk - (uintptr_t)dst; + if (value % 2) return false; + value = (value - 4) / 2; + if (value != ((value << 10) >> 10)) return false; + } + + poke16(dst_block, dst+0, + ((value >> 11) & 0x07ff) | + (peek16(dst_block, dst+0) & 0xf800)); + poke16(dst_block, dst+2, + ((value >> 0) & 0x07ff) | + (peek16(dst_block, dst+2) & 0xf800)); + break; + } + case R_ARM_ABS32: + // *dst = symbol + addend + poke32(dst_block, dst, + symbol_address(m, dst_sym, 0) + addend); + break; + + case R_ARM_REL32: + // *dst = symbol + addend - dst + poke32(dst_block, dst, + symbol_address(m, dst_sym, 0) + addend - (uintptr_t)dst); + break; + + case R_ARM_GOTOFF: + // *dst = symbol + addend - GOT + if (!m->got) return false; + poke32(dst_block, dst, + symbol_address(m, dst_sym, 0) + addend - m->got); + break; + + default: + break; + } + } + } + + + // find ARM-side stub function + stub_sym = symbol_lookup(m, "PealArmStub"); + if (stub_sym) { + // Don't use a Thumb interworkable address for the stub, + // because PceNativeCall can't handle it. + m->stub = symbol_address(m, stub_sym, 0); + } else { + m->stub = 0; + } + + // fixme call initializers and C++ constructors here + + free_thunk_descs(); + + return true; +} + + +PealModule *PealLoad(void *mem) +{ + int i; + Elf32_Shdr *shdr; + Elf32_Ehdr *ehdr; + PealModule *m; + + ehdr = (Elf32_Ehdr *)mem; + + m = allocate(ehdr); + if (!m) return NULL; + + // find sections (contiguous version) + for (i = 0; (shdr = section_for_index(ehdr, i)); i++) { + m->sinfo[i].block = (uintptr_t)mem; + m->sinfo[i].vm_addr = ((uintptr_t)mem) + swap32(shdr->sh_offset); + } + + if (load(m)) { + return m; + } else { + cleanup(m); + return NULL; + } +} + + +PealModule *PealLoadFromResources(DmResType type, DmResID baseID) +{ + int i; + int resID; + Elf32_Shdr *shdr; + Elf32_Ehdr *ehdr; + PealModule *m; + MemHandle rsrcH; + + rsrcH = DmGetResource(type, baseID); + if (!rsrcH) return NULL; + ehdr = (Elf32_Ehdr *)MemHandleLock(rsrcH); + + m = allocate(ehdr); + if (!m) { + MemHandleUnlock(rsrcH); + DmReleaseResource(rsrcH); + return NULL; + } + + // find sections (resource version) + // resource baseID+0 is ehdr+shdrs + // additional sections are in consecutive resources + // sections bigger than 65400 bytes are split into multiple resources + // section 0 (SHT_NULL) has no resource + // Use section 0's sinfo to stash ehdr's resource + i = 0; + resID = baseID+1; + m->sinfo[i].block = (uintptr_t)ehdr; + m->sinfo[i].vm_addr = 0; + m->sinfo[i].is_resource = true; + for (i = 1; (shdr = section_for_index(m->ehdr, i)); i++) { + uint32_t sh_type = swap32(shdr->sh_type); + uint32_t sh_size = swap32(shdr->sh_size); + size_t offset = 0; + size_t left = sh_size; + + if (sh_size==0 || sh_type==SHT_NULL || sh_type==SHT_NOBITS) { + // empty section or .bss section - no resource expected + // m->sinfo[i] already zeroed + continue; + } + + do { + size_t resSize; + rsrcH = DmGetResource(type, resID++); + if (!rsrcH) { + // no resource - bail + cleanup(m); + return NULL; + } + resSize = MemHandleSize(rsrcH); + if (resSize > left) { + // resource too big - bail + DmReleaseResource(rsrcH); + cleanup(m); + return NULL; + } else if (resSize == sh_size) { + // resource just right - keep it + if (m->sinfo[i].block) { + // oops, already concatenating + DmReleaseResource(rsrcH); + cleanup(m); + return NULL; + } + m->sinfo[i].block = (uintptr_t)MemHandleLock(rsrcH); + m->sinfo[i].vm_addr = m->sinfo[i].block; + m->sinfo[i].is_resource = true; + } else { + // concatenate multiple resources + if (!m->sinfo[i].block) { + m->sinfo[i].block = (uintptr_t)MemGluePtrNew(sh_size); + if (!m->sinfo[i].block) { + DmReleaseResource(rsrcH); + cleanup(m); + return NULL; + } + m->sinfo[i].vm_addr = m->sinfo[i].block; + m->sinfo[i].is_heap = true; + } + MemMove((void *)(m->sinfo[i].block+offset), + MemHandleLock(rsrcH), resSize); + MemHandleUnlock(rsrcH); + DmReleaseResource(rsrcH); + offset += resSize; + } + left -= resSize; + } while (left > 0); + } + + if (load(m)) { + return m; + } else { + cleanup(m); // this cleanup includes rsrcH + return NULL; + } +} + + +static uint32_t call(PealModule *m, void *addr, void *arg) +{ + // args does not have to be aligned; ARM side handles misalignment and swap + PealArgs args; + args.fn = addr; + args.arg = arg; + args.got = (void *)m->got; + + return PceNativeCall((NativeFuncType *)m->stub, &args); +} + + +static void call_functions_in_section(PealModule *m, const char *sectname, + Boolean forwards) +{ + Elf32_Shdr *shdr; + int i; + + // find section with the right name, if any + for (i = 0; (shdr = section_for_index(m->ehdr, i)); i++) { + const char *name = section_name(m, shdr); + if (0 == StrNCompareAscii(name, sectname, 1+StrLen(sectname))) { + // call function pointers in section + uint32_t sh_size = swap32(shdr->sh_size); + uint32_t *fns = (uint32_t *)m->sinfo[i].vm_addr; + uint32_t count = sh_size / 4; + uint32_t f; + for (f = 0; f < count; f++) { + uint32_t fn = swap32(fns[forwards ? f : (count-f-1)]); + if (fn && fn != 0xffffffffUL) call(m, (void *)fn, NULL); + } + break; + } + } +} + + +void PealCxxConstruct(PealModule *m) +{ + if (m->cxx_constructed) return; // don't construct twice + m->cxx_constructed = true; // be ready for re-entrancy + call_functions_in_section(m, ".ctors", false); // ctors BACKWARDS +} + + +void *PealLookupSymbol(PealModule *m, char *query) +{ + Elf32_Sym *sym = symbol_lookup(m, query); + // Do return Thumb interworkable addresses to client code + return sym ? (void *)symbol_address(m, sym, thumb) : NULL; +} + + +uint32_t PealCall(PealModule *m, void *addr, void *arg) +{ + if (!m->cxx_constructed) PealCxxConstruct(m); + + return call(m, addr, arg); +} + + +void PealCxxDestruct(PealModule *m) +{ + if (!m->cxx_constructed) return; // don't destruct if never constructed + if (m->cxx_destructed) return; // don't destruct twice + m->cxx_destructed = true; + call_functions_in_section(m, ".dtors", true); // dtors FORWARDS +} + + +void PealUnload(PealModule *m) +{ + if (m) { + PealCxxDestruct(m); + cleanup(m); + } +} + + diff --git a/m68k/peal.h b/m68k/peal.h new file mode 100644 index 0000000..accb0d1 --- /dev/null +++ b/m68k/peal.h @@ -0,0 +1,109 @@ +/********** + * Copyright (c) 2004-2005 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#ifndef PEAL_H +#define PEAL_H + +#include + +/* + PealModule *PealLoad(void *mem) + Loads ARM code and data from mem. + If mem points into a relocatable block, that block must be locked before + calling PealLoad() and must remain locked until after PealUnload(). + Note that PealLoad() may modify *mem. If mem points into a resource + or feature memory block, then mem must point to the beginning of + the block and the memory must be writeable with DmWrite(). + Returns NULL if the load fails for any reason. + Warning: if you do not call PealUnload() before your program exits, + your program may crash with a handle lock overflow error when run + more than 16 times. + + PealModule *PealLoadFromResources(DmTypeID type, DmResID baseID) + Loads ARM code and data from resources of the given type, starting + with the given resource ID. + The resources should be numbered sequentially starting with baseID, + one for the ELF header and section list plus one for each ELF section. + This is the output format generated by `peal-postlink -s ...`. + DmGetResource() is used to load the resources. Some sections with + no contents may have no resource, but still occupy a slot in the + resource ID sequence. Some of the resources are kept open and + locked until PealUnload() is called. + Note that some of the resources may be modified using DmWrite(). + Returns NULL if the load fails for any reason. + Warning: if you do not call PealUnload() before your program exits, + your program may crash with a handle lock overflow error when run + more than 16 times. + + void PealUnload(PealModule *m) + Unloads ARM code and data previously loaded by PealLoad(). + The module must not be used after this call. + Warning: if you do not call PealUnload() before your program exits, + your program may crash with a handle lock overflow error when run + more than 16 times. + + void *PealLookupSymbol(PealModule *m, char *query) + Returns the address of a named ARM function or variable in module m. + Returns NULL if the module contains no such function or variable. + A function can be called by passing this address to PealCall(). + A variable can be read or written by dereferencing this address. + + uint32_t PealCall(PealModule *m, void *addr, void *arg) + Calls the function at addr in ARM module m, passing it the given arg. + Returns the value returned by that function. + The ARM function PealArmStub() is used to prepare ARM global state. + The called function should take zero or one arguments. + + void PealCxxConstruct(PealModule *m) + Calls C++ constructors if they have not been called already. + By default, Peal calls C++ constructors (if any) during the + first PealCall(). You can force C++ constructors to run earlier + by calling PealCxxConstruct() directly. + The constructors are run only once, even if you call + PealCxxConstruct() multiple times. + + void PealCxxDestruct(PealModule *m) + Calls C++ destructors if they have not been called already. + By default, Peal calls C++ destructors (if any) during the + PealUnload(). You can force C++ destructors to run earlier + by calling PealCxxDestruct() directly. + The destructors are run only once, even if you call + PealCxxDestruct() multiple times. + */ + + +typedef struct PealModule PealModule; + +PealModule *PealLoad(void *elf); +PealModule *PealLoadFromResources(DmResType type, DmResID baseID); +void PealUnload(PealModule *m); + +void *PealLookupSymbol(PealModule *m, char *query); + +uint32_t PealCall(PealModule *m, void *addr, void *arg); + +void PealCxxConstruct(PealModule *m); +void PealCxxDestruct(PealModule *m); + +#endif diff --git a/postlink/Makefile b/postlink/Makefile new file mode 100644 index 0000000..dbe260b --- /dev/null +++ b/postlink/Makefile @@ -0,0 +1,22 @@ +# Peal postlinker makefile + +RM = rm -f + +OPTIMIZATION = -g -O0 +WARNINGS = -W -Wall -Wmissing-prototypes -Wpointer-arith + +POSTLINK_SRCS = image.cc postlinker.cc relocation.cc section.cc symbol.cc symboltable.cc complain.cc +POSTLINK_HDRS = $(POSTLINK_SRCS:.cc=.h) got.h stringtable.h elf.h elf32.h elf_common.h swap.h + +INCDIRS = -I. + +all: peal-postlink + +peal-postlink: Makefile $(POSTLINK_HDRS) $(POSTLINK_SRCS) + $(CXX) $(OPTIMIZATION) $(WARNINGS) $(POSTLINK_SRCS) -o peal-postlink + +clean: + $(RM) *~ *.o peal-postlink + +.PHONY=all clean +.SUFFIXES= diff --git a/postlink/complain.cc b/postlink/complain.cc new file mode 100644 index 0000000..81c13ca --- /dev/null +++ b/postlink/complain.cc @@ -0,0 +1,78 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#include "complain.h" +#include "postlinker.h" + +#include +#include +#include + + +void inform(char *format, ...) +{ + if (Verbose) { + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + fprintf(stderr, "\n"); + va_end(ap); + } +} + + +void warning(char *format, ...) +{ + va_list ap; + va_start(ap, format); + fprintf(stderr, "WARNING: "); + vfprintf(stderr, format, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + + +void error(char *format, ...) +{ + va_list ap; + va_start(ap, format); + fprintf(stderr, "ERROR: "); + vfprintf(stderr, format, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(1); +} + + +void unimplemented(char *format, ...) +{ + va_list ap; + va_start(ap, format); + fprintf(stderr, "UNIMPLEMENTED: "); + vfprintf(stderr, format, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(1); +} + diff --git a/postlink/complain.h b/postlink/complain.h new file mode 100644 index 0000000..f465b28 --- /dev/null +++ b/postlink/complain.h @@ -0,0 +1,33 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#ifndef COMPLAIN_H +#define COMPLAIN_H + +void inform(char *format, ...); +void warning(char *format, ...); +void error(char *format, ...); +void unimplemented(char *format, ...); + +#endif diff --git a/postlink/elf.h b/postlink/elf.h new file mode 100644 index 0000000..4a73d8a --- /dev/null +++ b/postlink/elf.h @@ -0,0 +1,91 @@ +/*- + * Copyright (c) 2001 David E. O'Brien + * Copyright (c) 1996-1997 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/arm/include/elf.h,v 1.4 2003/09/25 01:10:23 peter Exp $ + */ + +#ifndef _MACHINE_ELF_H_ +#define _MACHINE_ELF_H_ 1 + +/* + * EABI ELF definitions for the StrongARM architecture. + * See "ARM ELF", document no. `SWS ESPC 0003 A-08' for details. + */ + +#include "elf32.h" /* Definitions common to all 32 bit architectures. */ + +#define ELF_ARCH EM_ARM + +#define ELF_MACHINE_OK(x) ((x) == EM_ARM) + +/* + * Relocation types. + */ + +#define R_ARM_NONE 0 /* No relocation. */ +#define R_ARM_PC24 1 +#define R_ARM_ABS32 2 +#define R_ARM_REL32 3 +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 +#define R_ARM_ABS12 6 +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_COPY 20 /* Copy data from shared object. */ +#define R_ARM_GLOB_DAT 21 /* Set GOT entry to data address. */ +#define R_ARM_JUMP_SLOT 22 /* Set GOT entry to code address. */ +#define R_ARM_RELATIVE 23 /* Add load address of shared object. */ +#define R_ARM_GOTOFF 24 /* Add GOT-relative symbol address. */ +#define R_ARM_GOTPC 25 /* Add PC-relative GOT table address. */ +#define R_ARM_GOT32 26 /* Add PC-relative GOT offset. */ +#define R_ARM_PLT32 27 /* Add PC-relative PLT offset. */ +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS32 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 + +#define R_ARM_COUNT 33 /* Count of defined relocation types. */ + + +/* Define "machine" characteristics */ +#define ELF_TARG_CLASS ELFCLASS32 +#define ELF_TARG_DATA ELFDATA2LSB +#define ELF_TARG_MACH EM_ARM +#define ELF_TARG_VER 1 + +#endif /* !_MACHINE_ELF_H_ */ diff --git a/postlink/elf32.h b/postlink/elf32.h new file mode 100644 index 0000000..c74f643 --- /dev/null +++ b/postlink/elf32.h @@ -0,0 +1,157 @@ +/*- + * Copyright (c) 1996-1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/sys/elf32.h,v 1.8 2002/05/30 08:32:18 dfr Exp $ + */ + +#ifndef _SYS_ELF32_H_ +#define _SYS_ELF32_H_ 1 + +#include +#include "elf_common.h" + +/* + * ELF definitions common to all 32-bit architectures. + */ + +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; +typedef uint32_t Elf32_Size; +typedef Elf32_Off Elf32_Hashelt; + +/* + * ELF header. + */ + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* File identification. */ + Elf32_Half e_type; /* File type. */ + Elf32_Half e_machine; /* Machine architecture. */ + Elf32_Word e_version; /* ELF format version. */ + Elf32_Addr e_entry; /* Entry point. */ + Elf32_Off e_phoff; /* Program header file offset. */ + Elf32_Off e_shoff; /* Section header file offset. */ + Elf32_Word e_flags; /* Architecture-specific flags. */ + Elf32_Half e_ehsize; /* Size of ELF header in bytes. */ + Elf32_Half e_phentsize; /* Size of program header entry. */ + Elf32_Half e_phnum; /* Number of program header entries. */ + Elf32_Half e_shentsize; /* Size of section header entry. */ + Elf32_Half e_shnum; /* Number of section header entries. */ + Elf32_Half e_shstrndx; /* Section name strings section. */ +} Elf32_Ehdr; + +/* + * Section header. + */ + +typedef struct { + Elf32_Word sh_name; /* Section name (index into the + section header string table). */ + Elf32_Word sh_type; /* Section type. */ + Elf32_Word sh_flags; /* Section flags. */ + Elf32_Addr sh_addr; /* Address in memory image. */ + Elf32_Off sh_offset; /* Offset in file. */ + Elf32_Size sh_size; /* Size in bytes. */ + Elf32_Word sh_link; /* Index of a related section. */ + Elf32_Word sh_info; /* Depends on section type. */ + Elf32_Size sh_addralign; /* Alignment in bytes. */ + Elf32_Size sh_entsize; /* Size of each entry in section. */ +} Elf32_Shdr; + +/* + * Program header. + */ + +typedef struct { + Elf32_Word p_type; /* Entry type. */ + Elf32_Off p_offset; /* File offset of contents. */ + Elf32_Addr p_vaddr; /* Virtual address in memory image. */ + Elf32_Addr p_paddr; /* Physical address (not used). */ + Elf32_Size p_filesz; /* Size of contents in file. */ + Elf32_Size p_memsz; /* Size of contents in memory. */ + Elf32_Word p_flags; /* Access permission flags. */ + Elf32_Size p_align; /* Alignment in memory and file. */ +} Elf32_Phdr; + +/* + * Dynamic structure. The ".dynamic" section contains an array of them. + */ + +typedef struct { + Elf32_Sword d_tag; /* Entry type. */ + union { + Elf32_Size d_val; /* Integer value. */ + Elf32_Addr d_ptr; /* Address value. */ + } d_un; +} Elf32_Dyn; + +/* + * Relocation entries. + */ + +/* Relocations that don't need an addend field. */ +typedef struct { + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Relocation type and symbol index. */ +} Elf32_Rel; + +/* Relocations that need an addend field. */ +typedef struct { + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Relocation type and symbol index. */ + Elf32_Sword r_addend; /* Addend. */ +} Elf32_Rela; + +/* Macros for accessing the fields of r_info. */ +#define ELF32_R_SYM(info) ((info) >> 8) +#define ELF32_R_TYPE(info) ((unsigned char)(info)) + +/* Macro for constructing r_info from field values. */ +#define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type)) + +/* + * Symbol table entries. + */ + +typedef struct { + Elf32_Word st_name; /* String table index of name. */ + Elf32_Addr st_value; /* Symbol value. */ + Elf32_Size st_size; /* Size of associated object. */ + unsigned char st_info; /* Type and binding information. */ + unsigned char st_other; /* Reserved (not used). */ + Elf32_Half st_shndx; /* Section index of symbol. */ +} Elf32_Sym; + +/* Macros for accessing the fields of st_info. */ +#define ELF32_ST_BIND(info) ((info) >> 4) +#define ELF32_ST_TYPE(info) ((info) & 0xf) + +/* Macro for constructing st_info from field values. */ +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +#endif /* !_SYS_ELF32_H_ */ diff --git a/postlink/elf_common.h b/postlink/elf_common.h new file mode 100644 index 0000000..ee3a904 --- /dev/null +++ b/postlink/elf_common.h @@ -0,0 +1,299 @@ +/*- + * Copyright (c) 1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/sys/elf_common.h,v 1.14 2003/06/18 16:38:22 kan Exp $ + */ + +#ifndef _SYS_ELF_COMMON_H_ +#define _SYS_ELF_COMMON_H_ 1 + +/* + * ELF definitions that are independent of architecture or word size. + */ + +/* + * Note header. The ".note" section contains an array of notes. Each + * begins with this header, aligned to a word boundary. Immediately + * following the note header is n_namesz bytes of name, padded to the + * next word boundary. Then comes n_descsz bytes of descriptor, again + * padded to a word boundary. The values of n_namesz and n_descsz do + * not include the padding. + */ + +typedef struct { + uint32_t n_namesz; /* Length of name. */ + uint32_t n_descsz; /* Length of descriptor. */ + uint32_t n_type; /* Type of this note. */ +} Elf_Note; + +/* Indexes into the e_ident array. Keep synced with + http://www.sco.com/developer/gabi/ch4.eheader.html */ +#define EI_MAG0 0 /* Magic number, byte 0. */ +#define EI_MAG1 1 /* Magic number, byte 1. */ +#define EI_MAG2 2 /* Magic number, byte 2. */ +#define EI_MAG3 3 /* Magic number, byte 3. */ +#define EI_CLASS 4 /* Class of machine. */ +#define EI_DATA 5 /* Data format. */ +#define EI_VERSION 6 /* ELF format version. */ +#define EI_OSABI 7 /* Operating system / ABI identification */ +#define EI_ABIVERSION 8 /* ABI version */ +#define OLD_EI_BRAND 8 /* Start of architecture identification. */ +#define EI_PAD 9 /* Start of padding (per SVR4 ABI). */ +#define EI_NIDENT 16 /* Size of e_ident array. */ + +/* Values for the magic number bytes. */ +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" /* magic string */ +#define SELFMAG 4 /* magic string size */ + +/* Values for e_ident[EI_VERSION] and e_version. */ +#define EV_NONE 0 +#define EV_CURRENT 1 + +/* Values for e_ident[EI_CLASS]. */ +#define ELFCLASSNONE 0 /* Unknown class. */ +#define ELFCLASS32 1 /* 32-bit architecture. */ +#define ELFCLASS64 2 /* 64-bit architecture. */ + +/* Values for e_ident[EI_DATA]. */ +#define ELFDATANONE 0 /* Unknown data format. */ +#define ELFDATA2LSB 1 /* 2's complement little-endian. */ +#define ELFDATA2MSB 2 /* 2's complement big-endian. */ + +/* Values for e_ident[EI_OSABI]. */ +#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ +#define ELFOSABI_NONE ELFOSABI_SYSV /* symbol used in old spec */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_MONTEREY 7 /* Monterey */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* Values for e_type. */ +#define ET_NONE 0 /* Unknown type. */ +#define ET_REL 1 /* Relocatable. */ +#define ET_EXEC 2 /* Executable. */ +#define ET_DYN 3 /* Shared object. */ +#define ET_CORE 4 /* Core file. */ + +/* Values for e_machine. */ +#define EM_NONE 0 /* Unknown machine. */ +#define EM_M32 1 /* AT&T WE32100. */ +#define EM_SPARC 2 /* Sun SPARC. */ +#define EM_386 3 /* Intel i386. */ +#define EM_68K 4 /* Motorola 68000. */ +#define EM_88K 5 /* Motorola 88000. */ +#define EM_486 6 /* Intel i486. */ +#define EM_860 7 /* Intel i860. */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ + +/* Extensions. This list is not complete. */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ /* Depreciated */ +#define EM_PARISC 15 /* HPPA */ +#define EM_SPARC32PLUS 18 /* SPARC v8plus */ +#define EM_PPC 20 /* PowerPC 32-bit */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_ARM 40 /* ARM */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_IA_64 50 /* Intel IA-46 Processor */ +#define EM_X86_64 62 /* Advanced Micro Devices x86-64 */ +#define EM_ALPHA 0x9026 /* Alpha (written in the absence of an ABI */ + +/* Special section indexes. */ +#define SHN_UNDEF 0 /* Undefined, missing, irrelevant. */ +#define SHN_LORESERVE 0xff00 /* First of reserved range. */ +#define SHN_LOPROC 0xff00 /* First processor-specific. */ +#define SHN_HIPROC 0xff1f /* Last processor-specific. */ +#define SHN_ABS 0xfff1 /* Absolute values. */ +#define SHN_COMMON 0xfff2 /* Common data. */ +#define SHN_HIRESERVE 0xffff /* Last of reserved range. */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends */ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relocation section - no addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_NUM 12 /* number of section types */ +#define SHT_LOOS 0x60000000 /* First of OS specific semantics */ +#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Flags for sh_flags. */ +#define SHF_WRITE 0x1 /* Section contains writable data. */ +#define SHF_ALLOC 0x2 /* Section occupies memory. */ +#define SHF_EXECINSTR 0x4 /* Section contains instructions. */ +#define SHF_TLS 0x400 /* Section contains TLS data. */ +#define SHF_MASKPROC 0xf0000000 /* Reserved for processor-specific. */ + +/* Values for p_type. */ +#define PT_NULL 0 /* Unused entry. */ +#define PT_LOAD 1 /* Loadable segment. */ +#define PT_DYNAMIC 2 /* Dynamic linking information segment. */ +#define PT_INTERP 3 /* Pathname of interpreter. */ +#define PT_NOTE 4 /* Auxiliary information. */ +#define PT_SHLIB 5 /* Reserved (not used). */ +#define PT_PHDR 6 /* Location of program header itself. */ +#define PT_TLS 7 /* Thread local storage segment */ + +#define PT_COUNT 8 /* Number of defined p_type values. */ + +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 /* First processor-specific type. */ +#define PT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +/* Values for p_flags. */ +#define PF_X 0x1 /* Executable. */ +#define PF_W 0x2 /* Writable. */ +#define PF_R 0x4 /* Readable. */ + +/* Values for d_tag. */ +#define DT_NULL 0 /* Terminating entry. */ +#define DT_NEEDED 1 /* String table offset of a needed shared + library. */ +#define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */ +#define DT_PLTGOT 3 /* Processor-dependent address. */ +#define DT_HASH 4 /* Address of symbol hash table. */ +#define DT_STRTAB 5 /* Address of string table. */ +#define DT_SYMTAB 6 /* Address of symbol table. */ +#define DT_RELA 7 /* Address of ElfNN_Rela relocations. */ +#define DT_RELASZ 8 /* Total size of ElfNN_Rela relocations. */ +#define DT_RELAENT 9 /* Size of each ElfNN_Rela relocation entry. */ +#define DT_STRSZ 10 /* Size of string table. */ +#define DT_SYMENT 11 /* Size of each symbol table entry. */ +#define DT_INIT 12 /* Address of initialization function. */ +#define DT_FINI 13 /* Address of finalization function. */ +#define DT_SONAME 14 /* String table offset of shared object + name. */ +#define DT_RPATH 15 /* String table offset of library path. [sup] */ +#define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */ +#define DT_REL 17 /* Address of ElfNN_Rel relocations. */ +#define DT_RELSZ 18 /* Total size of ElfNN_Rel relocations. */ +#define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */ +#define DT_PLTREL 20 /* Type of relocation used for PLT. */ +#define DT_DEBUG 21 /* Reserved (not used). */ +#define DT_TEXTREL 22 /* Indicates there may be relocations in + non-writable segments. [sup] */ +#define DT_JMPREL 23 /* Address of PLT relocations. */ +#define DT_BIND_NOW 24 /* [sup] */ +#define DT_INIT_ARRAY 25 /* Address of the array of pointers to + initialization functions */ +#define DT_FINI_ARRAY 26 /* Address of the array of pointers to + termination functions */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of the array of + initialization functions. */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of the array of + terminationfunctions. */ +#define DT_RUNPATH 29 /* String table offset of a null-terminated + library search path string. */ +#define DT_FLAGS 30 /* Object specific flag values. */ +#define DT_ENCODING 32 /* Values greater than or equal to DT_ENCODING + and less than DT_LOOS follow the rules for + the interpretation of the d_un union + as follows: even == 'd_ptr', even == 'd_val' + or none */ +#define DT_PREINIT_ARRAY 32 /* Address of the array of pointers to + pre-initialization functions. */ +#define DT_PREINIT_ARRAYSZ 33 /* Size in bytes of the array of + pre-initialization functions. */ + +#define DT_COUNT 33 /* Number of defined d_tag values. */ + +#define DT_LOOS 0x6000000d /* First OS-specific */ +#define DT_HIOS 0x6fff0000 /* Last OS-specific */ +#define DT_LOPROC 0x70000000 /* First processor-specific type. */ +#define DT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +/* Values for DT_FLAGS */ +#define DF_ORIGIN 0x0001 /* Indicates that the object being loaded may + make reference to the $ORIGIN substitution + string */ +#define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */ +#define DF_TEXTREL 0x0004 /* Indicates there may be relocations in + non-writable segments. */ +#define DF_BIND_NOW 0x0008 /* Indicates that the dynamic linker should + process all relocations for the object + containing this entry before transferring + control to the program. */ +#define DF_STATIC_TLS 0x0010 /* Indicates that the shared object or + executable contains code using a static + thread-local storage scheme. */ + +/* Values for n_type. Used in core files. */ +#define NT_PRSTATUS 1 /* Process status. */ +#define NT_FPREGSET 2 /* Floating point registers. */ +#define NT_PRPSINFO 3 /* Process state info. */ + +/* Symbol Binding - ELFNN_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific symbol bindings */ + +/* Symbol type - ELFNN_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* Unspecified type. */ +#define STT_OBJECT 1 /* Data object. */ +#define STT_FUNC 2 /* Function. */ +#define STT_SECTION 3 /* Section. */ +#define STT_FILE 4 /* Source file. */ +#define STT_TLS 6 /* TLS object. */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific symbol types */ + +/* Special symbol table indexes. */ +#define STN_UNDEF 0 /* Undefined symbol index. */ + +#endif /* !_SYS_ELF_COMMON_H_ */ diff --git a/postlink/got.h b/postlink/got.h new file mode 100644 index 0000000..e486387 --- /dev/null +++ b/postlink/got.h @@ -0,0 +1,93 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#ifndef GOT_H +#define GOT_H + +#include +#include + +using namespace std; + +#include "swap.h" +#include "section.h" +#include "relocation.h" +#include "symbol.h" +#include "complain.h" + +class GOT : public Section { + vector mEntries; + vector mSymbols; + +public: + GOT(Image& newImage) + : Section(newImage) + { } + + void read(Elf32_Shdr *shdr) + { + Section::read(shdr); + + uint32_t *entryArray = (uint32_t *)mContents; + mEntries.resize(mSize / 4); + mSymbols.resize(mSize / 4); + for (unsigned int i = 0; i < mSize / 4; i++) { + mEntries[i] = swap32(entryArray[i]); + mSymbols[i] = NULL; + } + } + + const vector& entries(void) const { return mEntries; } + vector& symbols(void) { return mSymbols; } + + void buildRelocations(void) + { + // GOT entries may refer to local symbols, which will be stripped. + // Instead, use section symbol + offset in section. + + mContents = (uint8_t *)calloc(mEntries.size(), 4); + mSize = mEntries.size() * 4; + + for (unsigned int g = 0; g < mSymbols.size(); g++) { + if (mSymbols[g]) { + if (!mSymbols[g]->section()) { + unimplemented("GOT entry is an absolute or other section-less symbol"); + } + Symbol *sectionSymbol = mSymbols[g]->section()->baseSymbol(); + mRelocations.push_back + (Relocation(R_ARM_ABS32, g*4, sectionSymbol, + mSymbols[g]->offset(thumb))); + } + } + } + + void emit(Elf32_Shdr *shdr, uint8_t *&buf, uint32_t& bufLen) + { + // Emitted GOT is all zero. Use NOBITS rather than PROGBITS. + mType = SHT_NOBITS; + Section::emit(shdr, buf, bufLen); + } +}; + +#endif diff --git a/postlink/image.cc b/postlink/image.cc new file mode 100644 index 0000000..711fe0d --- /dev/null +++ b/postlink/image.cc @@ -0,0 +1,478 @@ +/********** + * Copyright (c) 2004-2005 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#include +#include +#include +#include + +#include "elf.h" +#include "got.h" +#include "swap.h" +#include "image.h" +#include "section.h" +#include "complain.h" +#include "symboltable.h" +#include "stringtable.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +// Max Palm resource size (actually 65505 for 3.0+) +// Note: this number must be in sync with peal.c. +#define RESOURCE_MAX 65400 + +// .prc header (68K-swapped!) +typedef struct { + char name[32]; + uint16_t attr; + uint16_t version; + uint32_t created; + uint32_t modified; + uint32_t backup; + uint32_t modnum; + uint32_t appinfo; + uint32_t sortinfo; + char type[4]; + char creator[4]; + uint32_t uidseed; + uint32_t nextlist; + uint16_t count; +} __attribute__((packed,aligned(1))) prc_header; + + +// .prc resource header (68K-swapped!) +typedef struct { + char type[4]; + uint16_t id; + uint32_t offset; +} __attribute__((packed,aligned(1))) res_header; + +void Image::allocate_sections() +{ + Elf32_Shdr *shdr = (Elf32_Shdr *)(mContents + mEhdr.e_shoff); + mSections.resize(mEhdr.e_shnum); + for (int i = 0; i < mEhdr.e_shnum; i++) { + Elf32_Shdr *s = (Elf32_Shdr *)((uint8_t *)shdr+i*mEhdr.e_shentsize); + Elf32_Word type = swap32(s->sh_type); + sectionPointers.push_back(s); + + switch (type) { + case SHT_NULL: + case SHT_PROGBITS: + case SHT_NOBITS: + mSections[i] = new Section(*this); + break; + case SHT_SYMTAB: + mSections[i] = new SymbolTable(*this); + break; + case SHT_STRTAB: + mSections[i] = new StringTable(*this); + break; + case SHT_REL: + // nothing to do + break; + default: + unimplemented("unrecognized section type %d\n", type); + break; + } + } +} + +void Image::read_sections() +{ + // strtabs + for (unsigned int i = 0; i < sectionPointers.size(); i++) { + Elf32_Shdr *s = sectionPointers[i]; + Elf32_Word type = swap32(s->sh_type); + if (type == SHT_STRTAB) { + mSections[i]->read(s); + if (i == mEhdr.e_shstrndx) sectionNames = (StringTable *)mSections[i]; + } + } + + + // null + for (unsigned int i = 0; i < sectionPointers.size(); i++) { + Elf32_Shdr *s = sectionPointers[i]; + Elf32_Word type = swap32(s->sh_type); + if (type == SHT_NULL) { + mSections[i]->read(s); + } + } + + + // allocated + for (unsigned int i = 0; i < sectionPointers.size(); i++) { + Elf32_Shdr *s = sectionPointers[i]; + Elf32_Word type = swap32(s->sh_type); + if (type == SHT_PROGBITS || type == SHT_NOBITS) { + mSections[i]->read(s); + if (!mGOT && mSections[i]->name() == ".got") { + delete mSections[i]; + mGOT = new GOT(*this); + mSections[i] = mGOT; + mGOT->read(s); + } + } + } + + + // symtab + for (unsigned int i = 0; i < sectionPointers.size(); i++) { + Elf32_Shdr *s = sectionPointers[i]; + Elf32_Word type = swap32(s->sh_type); + if (type == SHT_SYMTAB) { + mSections[i]->read(s); + mSymtab = (SymbolTable *)mSections[i]; + } + } + + + // relocations + for (unsigned int i = 0; i < sectionPointers.size(); i++) { + Elf32_Shdr *s = sectionPointers[i]; + Elf32_Word type = swap32(s->sh_type); + if (type == SHT_REL) { + mSections[swap32(s->sh_info)]->applyRelocations(s); + } + } +} + + +Image::Image(uint8_t *buf) +{ + mContents = buf; + memcpy(&mEhdr, mContents, sizeof(mEhdr)); + swap_ehdr(&mEhdr); + + sectionNames = NULL; + mGOT = NULL; + mSymtab = NULL; + + // Perform some sanity checks against the ELF header + + if (!IS_ELF(mEhdr)) { + error("not an ELF file (bad magic number)"); + } + + if (mEhdr.e_ident[EI_CLASS] != ELFCLASS32) { + error("not a 32-bit ELF file"); + } + + if (mEhdr.e_ident[EI_DATA] != ELFDATA2LSB) { + error("not a little-endian ELF file"); + } + + if (mEhdr.e_ident[EI_VERSION] != EV_CURRENT) { + error("not a version %d ELF file", EV_CURRENT); + } + + if (mEhdr.e_ident[EI_OSABI] != ELFOSABI_ARM) { + error("not an ARM ABI ELF file"); + } + + if (mEhdr.e_type != ET_EXEC) { + error("not an executable ELF file"); + } + + if (mEhdr.e_machine != EM_ARM) { + error("not an ARM machine ELF file"); + } + + if (mEhdr.e_version != EV_CURRENT) { + error("not a version %d ELF file", EV_CURRENT); + } + + + // Allocate all sections. They must all be allocated before any are + // read because of cyclic references. + + allocate_sections(); + + + // Read all sections. + + read_sections(); +} + + +void Image::addSectionGlobals(void) +{ + vector
::iterator iter; + for (iter = mSections.begin(); iter != mSections.end(); ++iter) + { + Section *section = *iter; + if (section && (section->type() == SHT_NOBITS || + section->type() == SHT_PROGBITS)) + { + Symbol *sym = section->baseSymbol(); + mSymtab->addSymbol(sym); + } + } +} + + +void Image::trimSections(void) +{ + vector
newSections; + + for (unsigned int i = 0; i < mSections.size(); i++) { + Section *s = mSections[i]; + if (!s) continue; + uint32_t type = s->type(); + + // elided: relocs, strtabs other than main strtab + if (!(type == SHT_NULL || type == SHT_SYMTAB || + type == SHT_NOBITS || type == SHT_PROGBITS)) + continue; + // elided: useless named sections + if (s->name() == ".disposn" || s->name() == ".got.plt" || + s->name() == ".comment" || + 0 == strncmp(s->name().c_str(), ".debug", 6) || + 0 == strncmp(s->name().c_str(), ".debu.", 6)) + continue; + + newSections.push_back(s); + } + + mSections = newSections; +} + + +void Image::buildSymbolStringTable(void) +{ + sectionNames = new StringTable(*this); + mSections.push_back(sectionNames); + + for (unsigned int i = 0; i < mSymtab->size(); i++) { + sectionNames->addString(mSymtab->get(i)->name()); + } +} + + +void Image::buildSectionStringTable(void) +{ + for (unsigned int i = 0; i < mSections.size(); i++) { + if (!mSections[i]) continue; + sectionNames->addString(mSections[i]->name()); + } +} + + +void Image::buildRelocations(void) +{ + vector
newSections; + + if (mGOT) mGOT->buildRelocations(); + + for (unsigned int i = 0; i < mSections.size(); i++) { + Section *s = mSections[i]; + vector& rels = s->relocations(); + if (rels.size() == 0) continue; + + Elf32_Rela *relBytes = new Elf32_Rela[rels.size()]; + for (unsigned int r = 0; r < rels.size(); r++) { + relBytes[r] = rels[r].asElf(*mSymtab); + } + + string name = string(".rela") + s->name(); + Section *relSection = new Section(*this, name, SHT_RELA, 0, 0, (uint8_t *)relBytes, rels.size() * sizeof(Elf32_Rela)); + rels.erase(rels.begin(), rels.end()); + + relSection->setLink(find(mSections.begin(), mSections.end(), mSymtab) - mSections.begin()); + relSection->setInfo(i); + relSection->setEntrySize(sizeof(Elf32_Rela)); + newSections.push_back(relSection); + } + + mSections.insert(mSections.end(), newSections.begin(), newSections.end()); +} + + +// if id == -1: +// write 'name' file in .ro format with a resource for each section, starting with resource ID baseID +// else +// write 'name' file in .bin format, ignoring resType and baseID +void Image::write(const char *resType, int baseID, const char *name) +{ + uint32_t bufLen = sizeof(Elf32_Ehdr) + mSections.size()*sizeof(Elf32_Shdr); + uint8_t *buf = (uint8_t *)calloc(bufLen, 1); + int lastID; + + // fill out section data and section headers + bool toobig = false; + for (unsigned int i = 0; i < mSections.size(); i++) { + Elf32_Shdr *shdr = (Elf32_Shdr *)(buf + sizeof(Elf32_Ehdr)); + Section *s = mSections[i]; + uint32_t offset = bufLen; + s->emit(shdr+i, buf, bufLen); + + if (s->type() == SHT_NOBITS) { + // .bss et al take no space in resources - no size check + inform("emitting section '%s' (type %d flags %d) at 0x%x (%d bytes)", s->name().c_str(), s->type(), s->flags(), offset, s->size()); + } else { + if (s->thunkSize()) { + inform("emitting section '%s' (type %d flags %d) at 0x%x (%d bytes [%d for thunks])", s->name().c_str(), s->type(), s->flags(), offset, s->size(), s->thunkSize()); + } else { + inform("emitting section '%s' (type %d flags %d) at 0x%x (%d bytes)", s->name().c_str(), s->type(), s->flags(), offset, s->size()); + } + if (baseID != -1 && s->size() > RESOURCE_MAX) { + toobig = true; + } + } + + if (s->isReadOnly() && s->alignment() > 4) { + warning("Read-only section '%s' is %d-byte aligned. " + "Peal only guarantees 4-byte alignment at runtime.", + s->name().c_str(), s->alignment()); + } + } + if (toobig) { + warning("Some sections are over %d bytes. " + "Consider using ld's --split-by-file to reduce section size " + "and save dynamic heap memory at runtime.", + RESOURCE_MAX); + } + + // fill out ELF header + Elf32_Ehdr *ehdr = (Elf32_Ehdr *)buf; + memcpy(ehdr, &mEhdr, sizeof(mEhdr)); + ehdr->e_entry = 0; + ehdr->e_phoff = 0; + ehdr->e_shoff = sizeof(Elf32_Ehdr); + ehdr->e_phentsize = 0; + ehdr->e_phnum = 0; + ehdr->e_shentsize = sizeof(Elf32_Shdr); + ehdr->e_shnum = mSections.size(); + ehdr->e_shstrndx = find(mSections.begin(), mSections.end(), sectionNames) - mSections.begin(); + + ehdr->e_type = ET_REL; + + int fd = open(name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + if (fd < 0) { perror(name); exit(1); } + + if (baseID == -1) { + // write everything together + swap_ehdr(ehdr); + ::write(fd, buf, bufLen); + swap_ehdr(ehdr); + } else { + // count non-empty resources + // resource baseID+0 is ehdr+shdrs + // additional sections are in consecutive resources + // sections bigger than 64 KB are split into multiple resources + // section 0 (SHT_NULL) is skipped + int res_count = 0; + res_count++; // ehdr+shdrs + for (unsigned i = 1; i < ehdr->e_shnum; i++) { + Elf32_Shdr *shdr = i+(Elf32_Shdr *)(ehdr+1); + uint32_t type = swap32(shdr->sh_type); + size_t size = swap32(shdr->sh_size); + if (size == 0 || type == SHT_NULL || type == SHT_NOBITS) { + continue; // no resource + } + res_count += (size + RESOURCE_MAX - 1) / RESOURCE_MAX; + } + + // gather .prc header (68K-swapped!) + // Most fields are blank because this is only enough of a .prc + // to work with build-prc. + prc_header prc; + memset(&prc, 0, sizeof(prc)); + strcpy(prc.name, "foo"); + prc.attr = swap16_68K(1); // dmHdrAttrResDB + prc.version = swap16_68K(1); + strncpy(prc.type, "RESO", 4); + strncpy(prc.creator, "pRES", 4); + prc.count = swap16_68K(res_count); + + // gather resource headers + // resource baseID+0 is ehdr+shdrs + // additional sections are in consecutive resources + // sections bigger than 64 KB are split into multiple resources + // section 0 (SHT_NULL) is skipped + int r; + res_header res[res_count]; + ptrdiff_t offset; + + r = 0; + lastID = baseID; + offset = sizeof(prc) + sizeof(res) + 2; + + strncpy(res[r].type, resType, 4); + res[r].id = swap16_68K(lastID); + res[r].offset = swap32_68K(offset); + + r++; + lastID++; + offset += sizeof(*ehdr) + ehdr->e_shnum*ehdr->e_shentsize; + + for (unsigned int i = 1; i < ehdr->e_shnum; i++) { + Elf32_Shdr *shdr = i+(Elf32_Shdr *)(ehdr+1); + uint32_t type = swap32(shdr->sh_type); + size_t size = swap32(shdr->sh_size); + if (size == 0 || type == SHT_NULL || type == SHT_NOBITS) { + continue; // no resource + } + + while (1) { + strncpy(res[r].type, resType, 4); + res[r].id = swap16_68K(lastID); + res[r].offset = swap32_68K(offset); + + r++; + lastID++; + if (size > RESOURCE_MAX) { + // section too big - do another resource + offset += RESOURCE_MAX; + size -= RESOURCE_MAX; + } else { + offset += size; + break; + } + } + } + + // write prc header and resource headers + uint16_t gap = 0; + ::write(fd, &prc, sizeof(prc)); + ::write(fd, res, sizeof(res)); + ::write(fd, &gap, 2); + + // write resource data + swap_ehdr(ehdr); + ::write(fd, buf, bufLen); + swap_ehdr(ehdr); + } + + close(fd); + if (baseID == -1) { + inform("wrote file %s", name); + } else { + inform("wrote file %s (resource type '%s', id %d..%d)", name, resType, baseID, lastID-1); + } +} + diff --git a/postlink/image.h b/postlink/image.h new file mode 100644 index 0000000..1ec4e62 --- /dev/null +++ b/postlink/image.h @@ -0,0 +1,67 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#ifndef IMAGE_H +#define IMAGE_H + +#include + +using namespace std; + +class Section; +class SymbolTable; +class StringTable; +class GOT; + +class Image { + uint8_t *mContents; + Elf32_Ehdr mEhdr; + vectorsectionPointers; + vector
mSections; + SymbolTable *mSymtab; + StringTable *sectionNames; + GOT *mGOT; + + void allocate_sections(void); + void read_sections(void); + +public: + Image(uint8_t *buf); + uint8_t *contents(void) { return mContents; } + vector
& sections(void) { return mSections; } + const vector
& sections(void) const { return mSections; } + StringTable *strtab(void) { return sectionNames; } + const StringTable *strtab(void) const { return sectionNames; } + SymbolTable& symtab(void) { return *mSymtab; } + GOT& got(void) { return *mGOT; } + + void addSectionGlobals(void); + void trimSections(void); + void buildSymbolStringTable(void); + void buildRelocations(void); + void buildSectionStringTable(void); + + void write(const char *type, int id, const char *name); +}; +#endif diff --git a/postlink/peal-postlink b/postlink/peal-postlink new file mode 100755 index 0000000000000000000000000000000000000000..ef1d98a0ec872c31e76157212d3e89c90a7be5b9 GIT binary patch literal 743725 zcmeFa4`5Wq)joU!iLMw;)Tq&7T@^GaASfydY9P5lEPo(67E>L!CVR%9G|0*=7(j(&5!(JU3_+qO0xK2eJfp+OI|~Y zXD2?pP$7SSCGD~tKdlJhBPipi1!;ar7u(=x3hGQj+x&Qu=Es!fzwR&HeQc7o`}PzM zKe;I2$CO`+a)9^vXYij{Suy9#%F+>)6;*YMN7h!4JWJIDY0|gJ(|uBxbP^}~I~1RB z_>91ZyfgoX=pSSC_XYSq0iUDsQJhx=XX5K@e8|V+RF-uvzR$tuJbX^aCkr3`%f#ml zd``mWRD6cv!}d?XXE;6{e9p&bBtE0@asMOD<{xQy|6@PQzeCNBxNq|4h`2l^)9^VA zpJVYk1RwH>|Bg{#A~X7@^;P`%3O-()k*dG>bvQnQ@j00Z{5uh!rSordp&@u3_Y ziBAST7#io_DCbx7$IJTXUHE1lLrJY62v>B+kM9-aOj z%GYm6@o;R9fFwPDZ~mKu5AhwW>H8@<#Pmt1zY*}1o09;4r^b(BDZf;wt2I44bb5_0 z|F%w->hgT#^B?7v_+@h7%ZwTE^53`dVfpXl=>Ma}_ogm4a>Thn_$xGgp-#V};osKj zCSCpuo&KRNAC7OJH)? zrPEL7bQ#haTch&Of^_n7lRn&P(D2u5{JV8~sBU@jX~Sm~)`~YYeb)m%(}gdn>zn=; z0iOTNct5O?qMu0LAsU|9UjBiut@W4AJ>v{2+HKU0hOJQ|2$Psa}M< z>9cA}X4&~)o6Fx{n^k+>-0B4jOKQqY)~wo`(e_LfIIvElByX;b!fR17%Rl*@LcU6lAg^en_p37`u6pzMHn_2oO9+D*ZOP7 z@k_2Po(Z5@e_2fqnOTPMDK5RPs$@aMTvV*}JJ65$_=}4v77LU_;Me@Q zK*`i-tJqhyr~)jVSyo%Opp0O171)BZ1q-ULEwkp$FZ0)0;4((RS|CGgRWAhA`4*_E znOk0C&2@5tiMjaSswpdx-&J!LUdIGw!vZeUwSc>}%umR<3l`$56xgkK3+w!It$B-T zD*RT1hM0YZv(FBg1*VqWp+k(~Ijm}u7} zJO2$tifQ*}KwK%)ZYY&b(zO&W=B2>yN`@NeilT6^7XKyTzmqYasiVF4uZ{DzS?ir+8>$M73Q&{%%Ma2n6=!IqWHZy1xg z{Kf(`h2Jokrt;g1@!h3L7?YL!#sa>O z-)CTr;x`P0#rz&&SvT+-#^q9e!*E^3Zw&BqenTEt@EeBfN`Aw5UB&OQmbHf8Fih{@ zH^$8ud_Bl?0`xDE0Vyo4CPBS>%J#;7jg3DI-P>x(Vf3~)C9tI+mGp3??`3+W zq(?Emp6R8M9>erTrWZ0G9FF+EDsQ5k9X|3aprPtbo!&t}@gbhD(dVmh7a21%DPoyqiiNtZM2 zWqPfoE1Aw>dZnZnGL0Q4`Y&le(_@)lDCxyaXES}3q;FuFThP{gNiStOpXqE#FJrop z=~0qi&h%AGdnLVs>2jviCB2gAg-lzLUd8lcraQXW|20f6Wx7SucQC!2>1L$CC+FYj ze|;nPkHDUe{DPU~*|z|y`8z3|OD`+;oP@n}EttD^EmBb9Cv2gP}t$e`?#{KtuA+?nU$6&)&_iPHSe}Gx z3jXdr*tXX<_>ZIvS@>~CQ}PhzbvGNBcg$m8zZBas`*&WQMt86>H}{0zy;jFd#P*r8DN;K=l7)?mr< zM#e?6yplB}k`>Jwf-I1d6`@{nNXb&Ur$;Vu=bo-|hew9EbBC+kk&(mQxg%BXs7NP7 zz`;98<(?IJ&7FIe=1f-D?g%CiiQI%GCS-d84Y^@odoXuMaxh~^qzdavpglQcw+HQx zwre%$VuD&hyECw))AFAhvO9@j%Kd=t^!UM1NspCuQr$t@>^GCzlJVDqB)qw-!GDT| zI2jN!E}l?+K8Q4}WZqIZ$GF?6LXu7?mdp3p! z0ti0rB_Gzm!&$Jg+a-Gt4CHVZA?05IT@K}Esjk7Q z024hAVR0* z0cgT@xZ2t%ESU=0uoTY=*3U*&l{ePO`-X!w&@jHqnrY9Pq1p&EWH(t0kp@Ai9!W7( z?B&Rr60FZe&CqK8)yzq12s8`|G^FAG&5`8IEy=?g!?{BS2kQqDQvNzc?#!UQuF2lP zPK50ApnY!-q+bu(%^}|orx|MPbrcZxJY=UDLEFVqE!q*X?`DR;rluzgM02DK%nELHm!j~Xu)U)jqkpf%dD@Rwo`-ksUm*zSMuCBR0f;hCt7LyG9VE3aWr)cT83VEF$f)A(F#Q{ z43aekxv;6y@dZ^!(Sxcppb>&z1kiBV-YdURT%>H}%qF`FeX-gKjg{iqRt?blAujPW zE$YthQNC8nNo3{SR2oplq3i-Oi+MZX*9hBP?lq}w7}umOS(EBkDw}IopuM!oZXgM* z%kf8A8OsF_9i-m)5Pk{TN{uj0D66TEDJY=8lI;WQe1;|mI+Zk~hoAsGu%^VAAr@Lo z9!!*T$Jq^aC-$iIJbWx@gFOi57liEwP4!rIsiw3-Xe%P|P!I?%;zHcD)>#?t+aOmq+vXb=j{7YcSLzJ;3XUBazJnBazh zU50?|SkA~TX#3qH;Fb4C0JVLRe-Qq9(&{fT^>VQyn0hTP6mw_YeHX*}mUV(gIlF&t`II17UV zRDWo0i-2G|Q3zH!-EBKDXg?4tdVt0{FyGdJ=8*C|Kv6sgsj$7vEgW}(-{b6ES~wO! z(LnQZc-n3-W3$Kbc=##8FQ{ClbthszL+e7j4yemB+;yNQf^64_m>mryS??ws$V@^S z>CM;L&&bYaXp~A&*@5LEz4WVCZ6$`l4ntrFJ0c3t-VpwW@Z8Pb%hv4>nk>j090?;& zQDAEQ2!jnm)!vG1TK)^p{0=vp76}y{N`h|*G?rdjB%T4x{xKNZ*`O!#(ZARln4^a_ z!U1^p0w9N8@kKB(W$X$_pRho0=h);eQz3wMr}WDgwD*LH_JGMm@XXsB!98390auGu z$k!=|@{RBfItc;-Q171|L2p3Y-~3yodlmX2VxgyDD>~L3kihD3N(k^ z0U~W#oc+gOi5}oj$6pU8cSllM{ZUcK7k;89WsRPc@1(2!E{z$DY=Z{5UW4q=Ais)& zd|!hs(;&anAm53CQ~`vfedjF>;EpC(hX8J}8xI0ZSEz1BXvy}_w8r;;k#_r*v>!Aq zecbL-LZl)q-uirGgzZO#FQAq` zVcBqV@jFOKSXoDFT2bO#8xm-iGan$N>TPftn>-Eq>j+G*6NB|r*v?P+R~M{CK~OT< zhMM+}6}Dx!7`8W&f)3=gog7SPac+l;V z4B5`Qd=PW&J1D2A7%T>jn4d_970PRahn2%*8yt*_N;5P<<`C>gP?q0>DMl#>PNT%IlR1$S9 zMwFTp%xf{=ulPu*^zr&3P%LM}N|qGNL4lI2kjzGMp&48V6~UD+nl#W3D-~x7{F6OI zd=DM?4O4!MYTq<>=r^e_MTfPnmPL?2XQe#^y99Q9hg79{q+zq25^Z-1hOt;143ZD) zz^5ghhos#iMzY-r9T{5M0VUJjLi2o@II6Vb$ZquEG=cGQ5jvvfDq(o+@F zLb|ljNiG3lGk6#I=gSlYQTH-(RQ0!BiB&hymC$k-!-7Q%+P{*I((G6{B>2%y|7sRlq2jb;ys+qi*yU&o~G;qun>L4 zuR`ZnzW$Z=aCY+eo9a$NF@C0ux9g5kKMxu|weC>$^WgE5{Hf@BW(a-1?j^wmV9)p@ z$sWh-IZpN=I{Q*)f6d7rgluuvLYC>Qtzz+Tr})tEC4y`@vyax>Ug0(E@ zdQmn0NcJ%($dZCbS@2I)5X#OBbS7x0Q5BQJi@GS49{!vT)4%OpieC{WP&;?;^g^nU zq4UNP^1~BVo|3@NU*kv*H$I1$v0e@Xug6$liRyZ+Z$P;o%M=7&s2S)Q>x+(e%0E`9 z_Gzq-f{3FFU-DRou`yR75Hr@-I@vK}UF>8h9P4bSIA*Me>Fge3o$eIGjrB(_2vxm} z^)6M+VGDiYjP)FBlzNW!Z?V+GkM$s(r^foof5eP621Dkz+Uguf5@`1dq*FF2Y*@kW&U=N* z6q{X7XbO>s@(0tt<>|-!>tF^WE0{kx(CDSJj5J?<88M~cnK$%#mV0IfSNR@*k zn4jsQ2KAe$l`P>fTd>0UFtI&BYB`64Ayux@hL>QNOzD4ubhXkV?ndYREkWL9C(nf; z70fkU#}o%5@JR5uOSYR5?2a>Fy9Hlz4c3z=4DJdvW?WgcCD|g6|6Aw;vovR;zeGkw z*r2d!tVceE_QbJuU`dzd9~$z(*B6@B6-)|YD}?U}$)SlJ`QZso1kbvH6I0b_L~(*y zV*Lcu6=%T3A>bmjVN7(wHz7kXcu3@F&C4MUFI}+Nh^}x0-xC82zN1BvBh(QYf{4R9 z=|&?sQWc4RK_y=r#^dnL0fEM3wRQ*Evk(S=`bHKm1E63*BtU1_7jYHMH$^y(@6xox zNz4hg6h%=9!s;@cxpzc!F%1lFx&Mj$R8HL$Z*ee{PG@0PaDd>5@=wVlNh2A+c-2b? zY@ts(?O_!G^4}tH|1EU(A+b1V2dSFP;K8$bjf9?4G5xWv+e6b`c`3Wl?hQT;+=pevA z0YZbdJ_AL>LgaoAgF;Q6fic{oqHzu*tFT56XysXrhRX+>{&{6zRdSZ{5T z(JF7@d|9{h0e<#M*elTvJR()Px;6n~Ta zWvwftSZ?Xr8bnmFp{-VvG&M@y<$b~DX!yZV_|y7=KT5;5O5iJo4RM*5~pD}sR*z-PfHCKwZMz~>T)?p<;iI(j5bejs?tAig9D;7T7m}!JHln1 zSAN6TEnEd-xYdH?si%~bld^q~lG6dFJ9AE7Ra{cS^K)HgKwni{QqmZ$@-$DSdn3#x zCEu4SeMm_J8nRz0De2i-PboPyO5Nzb;Ej}gxYuDoQeW^!O11%hpQWS~!}-OfM6Kab zTN{p7s2io_p_j!#`CEd#mz_Kp2Dg>%*x!2H+$Sshf1VCf5VJ(Bm2d~Wu>nJxvT5rn zZwz;S*xJQ%%ZCclyck?A+cB<{*Y>xS+xMZB1nVOAJII#R7Us(f7{%D#j;ztjn(y5< zTC1x$woxw@&2qr?ZP9$!K)5WLQPQ;-Tgqi|4T&K+@#_EI(8~hELCCtU=Lbe*KYRJV zeAksgdjFUAcq2qR&G=6C%a%`8#<|P}@w#B{#(G_P?AiYt=EyR{*2o-DduAx+z?Ru& zr*JE{71G)_fvo&D^ly*p-@fSp%E!eq@_|uK=ws_K+W*UEPLEYP8Jy)}%>`Pm)%~p6 ze}H>=zgO)^``gN=`_M`PSw0}6w@)j*oHM(jH-98GL5g=HPa2yu_bw$@UFJ+=zw@%#i4O~QYaU|_!#9F>5A+qQjqJm_B{ zPl=%*W-l|?Sm|c}mjyS)J8)B&{e>24IJezvI9G37f}WU?EM$d!PGHAXaP*62z*!Ta zLvVshV3C|xr4ETah^oxO{CQR#lJn;gg3#HGiOkH!#58m2i^@#@{JKJndP6}Bzh)YH z{{Zl77kIF*{JNxXew_`!_y0S7T?gl(X)SI?Tq8x$cn5%A$G^Gn{8|B7)B+oouLD5S z$o-&cZIq@Eu4E|=IyBLM@F5sv+B?gqs#|$nvYL>7Tsy<(5*eud_v zM4;;{mV8T(&|%2fUDl{Zli_DjLCKWPdilJ{ZIv(FTKarxa3I(Kh!(|P#* z&`ECk5a!|0Q$tof9hfGkF%87+f*5G08y%Om&F;oMT(|K^L>R1}$v|)}Ni@=69tx=Y znkO+b2!UsU`&;x7XKJVV0wyfE6+IhM8CY%y7Q}$?J~=1%m?4qR;D-%%1R4i3*eUMR zVVnJ7(l+}e5R_rg8W<`XbHH#7Fv`-hC+2_wbaKzC3E2Z%fK*9OUSNX0L!j~?j8$~Z z=dimas6xpj`0zQJMz}TjG!5E90rR33R`%+v~7)!woDdW~3 zE@Qq>Grk3@ThteflTXc*sb@eDPiHbh)6&B>^U)|b8FDR;9rzx|V+ls&gBEZ@KL-ML z`56p}={F9+ddqSUlg+6JsK3jlD2eYu>O^pm5s5$GP3dKCqDt6zuWQmC1!x(QdvQrR z>|5t5+JPH9QnZe@18{R%h-26}`n4Bd#`ro6Btol0`oca2ugfUi2V$kR%kGlMcEinK zSZ#D1`e5l;!hOzWU}fwBPpO<$W+RA37N4HL6EI51UPle*ds_LFCOsFPMkm<++ob=` zN&nZfOq03VkhwN!ZwmWxN$Z1iT^5ldaxR@2T2@i}rOttTHl5J0Nq+fppSE$d$ zu_zGmpk1cSDT()LjxqvNd-9tCosY(I3YD)doYXB0~Y@3L&Te&hC1hF_DM|iqp{C;6&yKG8k^iAFL^h`iSr0C zkuc5!LngCM>-jq|0){VP`<*amxV~FE8$^rvXw&m;x9RyChf_KpjgeO3mC@AP@R19z z?;Ymqsh+IxLb<=)b8C6OgV)#&5Oe8X%qeEuSM|zN4f5IfXHZXP{UySmBEC9jCsrz4 z+1g?Hi9v_##9PyhR?`q@lMset$C@^0`=O%run+UbnIkJfhVW_+uSfYZ!qZyRZI5=~ zaMlpUbO=<7T&YS8`9$0v9|8;{ z8&h3G8($gZOc0w8T8{{+BWiBG)8p5D*nn+mn$Ne8NK7CkVUE_dI(ANCU%;PZxki?0 zL=M;FB+=~)_@iEKG0Xe)1)K#~jWEgawDv6oizixOIkoUe7hVk@#Ka9+ zl3~x~@@5d$CWiO(D^mYEt)0b|IT)bI;E}6t$H-N;y+raL5Cb2o4`w}Hjx9)hQ4BT@ zteL$i#(tlcrVw_28KaQ|)jiM_ZO5n^vpVZmWZ}ka+wt0_dI#x0rsFX)>_R%D#rEKO ztuB040rS=q2+KeRoI4$2O`?)BXWpJ?S$~{j5QXi}S!Ka<=!={*F+=O2PukgaDK9~} z_C392K+BbXN{py(jF&Ed1?8e8j0|RR()H9P`>;3v;usRIjU%}BWg*ZA%U>#gVEIhA zPDWS9r}kxa49Qeaw4XTvA>PjFn9hV*9S1Ve&+2&Ct^>6?%GxAq+{8*h^)#j5iIoOp z_AORgd==bNA=srCi9+s)vVh8a(_j9O6Eqw&+x&9X-r2O|;- z(|VvV!H?L5Ijam5I3BQ|L&o+%|Nc{jjO~U9$L#2?M0sF`ms@ajh25LOG#*c8aj-&=WtF7(eCVQo*Nj_^0o4&oMRm-c^#JTrX z;^fUf*V26+Rx^2yj2Q7@`vF1@kS;&KM*wk?@&fxy(OC|4!U4upBI?8z7Cy-Bzo&OX zs(fq1Hi6S=b>OLHXh?3Sv+jqA5g~gm&=L&o?8e%NXZ-MI35es)&4b6{#O~Q|#az)q z*Aj>ny=o}>5Ez6aQmUg|!s>d?g`h}A2G@cKFGQ(Jo6hKz7^1ML15vM%lF2|Rjl5|Z z`Mzo-?8BzdvBrh~y$CxteG%F8IYnohB5d>8!#44N6A_}rrA)SQ0)iG58LML~^7QS8 zjNS6Ip=6$>6RZ?AxSV70;*bONHlhQ=8TEjXnUar3`gAhU`Yv<0wwBWmpyl-*$g4cn zhhEIIW!n?M+$b~7na6Bj3QTHUkdx=x0>-O{w+r#h~2;a*kJ8- z|CWto7k%^et{oWR1pBwofCNspe)ey0JK@p`JtHURP48UXiKDpVwvx^nha4`45N4h8 z9B{+_c*z&bQgeA30IwM-a3-Nr;ex+VCR1I4F=Hs(WIFti1U#Vmo1IfX=P2(drKvB4?O zuCfCWSegwqB}LvhQKfEu!c+=GV1aITp0&})(x0F2p^&}oVF+jKCb3h zJ8s^%?8i4CbW!_pv8)d9_T#fZgC5xr`|&Jb>0v*f1arh~6mMh~Uc(fpWy^yCSZmLj zNw*I9Vy$g-+mAb09*qm ze-Jt7cC7uFtXsyzSM5Eq_G6kUg8dj#{%fc%x9|E^YzVaP`fWJ4MAUjlg(b8fzYA4^ z=jW2rlh{LJKMEJwvdW?TC_r884uIT8D*vwics$X^&X#!l@n7gp-}d7Sm;Kn!dFjf# z(4K3N_=4x9t6v2=qvMw|VRYB^O!T9>9zURV5$}5S@CP3Wb4{4pr#<2C)=)j|iP4+2 z^7TSFBa?Comz_D!Cpx`)ieKL>(1J-ETa@hC75Yha_JL3TgoSos_@q{9wG4=VfU5zP zfwN&wxO@YjTfIh3Jc9MtK++e{6PFvp#Fb+S>IbqvTo_>!v9@EAk~^XNF(zO<3wqi9 z!xLVL6TkoXh&8?*Mm_2vgA1~D1`b1i=t*42?rk~&JIX{von+Za{yIv+HyWlM81P3fpLrO ziln;OAjCslX+ElhA@OiGKwA&nqN1oIB1j%~0P2tZoC}_WQQi3mB3B-9!fT&74m~#U zgooi!*roEc#KUKX>h5P6w>NgDJJha`XCNw4%h@hYe@FKfN3{~;SF{EQVot%H#?p($ zxplgP@ZmISBMx`iir$Wm{=1MD_C0T!o&kcDq0Bx`!|lY4VVk8fcn_8yKF{g230A7p z!!zs-cPC?xdp-c53-hK>QK~xMiNX9JEKPl$GslHF7A-owkte}LtKtcJrB!vfD0=uc zj9wn`9gy5dnSvj0!!Z1z5HWaB9P~e-gFf{(Hm}_)vWeZsb3aVF4f13boPupQ-`?w- zf>jFgxKpqzabm+*IP);&^=x>s^k%&Y)pO3AUV#oFTZ-1Zy%_QU%2pI1gwJ*0q)x${ zCxtes-bzFt!ujODX*ep02)|*5^akC6?*SRl^l;sZu+36BL*yquK|e@d{)Q(ySpK^dWO`sC!GXbDjD*$oW#8@zPlHQb zrVY1su6h1rRnL)bw4C;^@15mPU5LNnaSmF=m&9j1=o))S2a4h$FqO4*&?Z?c>wP-k z6wo9_NU!!rI_-^9WK|KKA)b8|8UUqYuzU!qlitC}3fHZ+J7fX*J$L%Cc846L4@4Do zS?rDvjosmdxTpMDBkXB+q-(o_urYQ=Z5Q>LJW{V(zWS|C;ltgXMA>@<)qY)lVsIm6e%9!!B2X1PHkLyg0`Nz&QBQnN04z}49V zCdktU{dxdK7nNyvT?w$VG{yw^vtWLjm``wFjxj;Fmc~;wgne2XH9S^gfK|{7Q5~-h zk9%o&P?{XW;}0}EZo~X=;;8Org=tSH&2q0XJnnTH9#5jQ$MMM^P~Z-~Sw}oS5yJ!a z@LI6b6@K%x`xP^a*1_5?U0FE(LyVw?*!g;c&&(jMYss z>I+b`eV`twB^;s36Q+v=bFb8gaJ4Y@MvT?9?1(xCLKhrMqy>;{y=bio@OQdUrn{g6 z{3DdY@M28<-VKv)wJB`%1e5NFZE~FHj$@lt=w|i&>S>!ijFTa4o4ouhC7TJZ*(W?u zd2$P@%E0;cS&7&t!htzX4s8W`@c{^9cOc00P*@io2xIItNeFb z6ZN#YUWOJ;WOLO?{C{sY*ZGLz(dI$CuV-Iut~C@S+;(pm&_aoc`no=2UP|(BXIt=@$5Ekfoo9l&p z6f+XoTyH(3`P8q?^#imh9Cg`TgMk>s;j+0ZbyNFhbM3yH^?TY}9yxG#+gur@3q5VF z7jzf)!{*wCfFJfH&gPmXqfH~?9JwS(CnLfwYeTL5dGO)`W~BOb8W() z_F{9rX>fk&HkbGmc(Xt(GTMxfpDvzxz6(M>G%Is+1n+xrKWXo@4`mYIeI2H#+?bq8 zVbYt|9I7`)&c<1xDSZw56W)1Y0OvrUw<0Y!B4=Qa0PMT4A5_n3GZE9OF$7C5`jso@ z^S|5IC6-y7mC|~L5`#D^WfQXh&r0dbO1XNiR$M);l#fu9$Vz$lE>Xt4c!nNCsn&%1 zY^BuylNwGuL#cv%f31}7VCN-`_GzVTGFMf4wNg$s#P@2YOnEk;mGa1)nt=YTluS87 z63@_ysI^a4N})k7jOooY#9M%L7-8%D_)nvl`?XU1I74!KhJHw$D%YWiDoZm2p)QOgXg*sM`B%rJM*OKwBvflMfJpsFkwL$#JZd@9V5D%}Qy( z;@6jzvJ@Q>9nqVWQf~lywNef?5dB#x$xlgJj+K%N+Iq24T5*CPWPRyYim~*1eZtZ= zYB5errXGD8 z1W@?nZf%U`fXl%XSD8|{nR?#(9b5xM`*CaItH9D@3%nIxl^(Y?4wnvYRFN01TN{%= ztSl})Z*9B`Peh-$Hje*X3(;CRWs_SQt5#Dj%1K*@O^RBCYh4}4>chtmRyjabit(;n z8ykQ@DB6GlapD=|)N8j35shZp8rDPklrH%l)oINy4iEz<&a=4Vpt&OvER)VEOJykJ_ zqAbD>8v4HVd-ZL?8ux68zqN6j>3grYe%-e=JkdvNfC`HGb&vLZe8|9sQEz?E8k1Rr zSKVC?9C@bNUBh|$hR8@cn>il4MoG1d!K4gYVBB;#86u*N2vccbxA z;T`I0r}|=W9Wr-gCBR<1<)qs{PKtMHin*B(vPk-w03zx406i?$z>;Pwt-cujhckdW zwYhbsBpL#duLbMdKf&bt6aSu(cFSlMtY#vVym}ANcegazyU4oMui~$2OpbeK(x_7hg zx@g_)t$2ww>hA9LpBmrp99{Rxt5v&YsM~gpY82$G!WiJ5aoZJ|j21k4046;$>-pLs zzCrU({Gnf>8R$&*kBo0(scxcNH!*-sV8ELrols#EpGN@^dt9>{u!t52ENSSLhj*sc ze;c*#&IB)p*&g|Z&m@Q_$ke3tz>-~-KP6I5g}B6H)eVWKV4J4kjSAJtrGUf?60b`t zR!NR;BY9hg2eLL|Rpc0@E!)7s!`S>?$lJl;*$EayF$R`Ith(bF7m2*3z}i&b0WQcG zk4AI>#1`+~wjzIHH|qDIhtYkEc6*917ujR*U%&-q@9|mi-qwORt(0a&PfL?}-KlG3R zBy2xI3{!xVKjo0TgUh};8HF~MaJ0^HmanJtimzN}n@8}9zZ4z{Cg4d!t{&)u_fSib z--g#XNkcOTi?@qMd#el1ML~R5YeZ@yBu97%E{5y7$Tbk~IFZ}!c&VAC#e~PFfRnlH z@El_b;5Ec&r@mjumbU{b&d24psD4v?wE7Ly z&m#8}>}dW$ki@o;F~jRL`4+-d^a!u!@RQ(`7{rj^;f+lF=3emy(hCbAlo$X^Dd4pt zug!B-k2syN2F%jyN?ggGO&#D0W#_ABMY;b*@43O#;+!Z;(_r}D669@m^30Q`*d}At z^f0_80CL_RSF+ud@SM5-_v@0j7?+U@iA8uPt>Xo>7N=-?tQg zQINPp5lz9{mCm?|^}#4tDib((@J9`!GOv+ltLE7|e5hP!sHl^m=t>xvf=r2YJO;8< zNCf$#AMv} z=XV;Jw>#TTh}EfW;133gAuq`GEYDn1rkTkv237UK$`9qK;8dYnM zpM$R&<}ZYy>)|7#UXK45l;MF9N+}FNzs!q^b(PyuCEAgobR0@2Y!d~dT*(A?Yc{CY z*zN!i_!LYsL}vvRTQ~dAFDyhk!5fObZVhag0&qaKW3H|(?yFnzVq11p$o^F%74X1DAERMqHMoLeRyrFEC^5_9Plpk0 z;4X$&Bn<)dkTvJN_degiKMpO(1pShqL?yG>ZF_z1bGe%}oa*vqoE@>xT6~eE+Q-U3c-Yt5@#Xkf-@&-b zw2{&K2cWslb?)d5K+{ZO*l)iQ`~2%<-?t)Ev_j|JjND++ijcj6FlTe5l}5alBJ22N ze*nZWe%V8@my9d}_TK!m(^dwj(d2VKjd3c;<7N}{)QPjb<|Aez0JmAOY$FMI?E@0x z_+|NkMG?EbdzDZW#rS1+vC2cJ(&y6{w_tvWK&=(O>*eDz=J2dx*#YU&@t0v zX*m<^pvP?knX9DbZ%_h|maxyc#K*VwlEuCap=le{^*u*YZw6X@TW`mE{3!#S19HH1 zzDI%*5rsy6B)O2Hq1Z0h{BA=@U#bO<*qINz@K*y+rrbV0A?Qdn zrz!dkSuApZwMBf*cR4wZuX%;ea{HROUMX6Igg4(+v?*S_2wv$&2&t8q)a{!uy2kV+ zs$b%L(OUr`qTQ=6`UI@KSeLXfHkqDO{T>aqcU~?Jazs#c*K)=yaka;jTKOY0h=;ZE zM@DcWv=20)sG2vjENe^>{1T@|^ZtxHO3>`f&~*qDc8#m>gzZSd3=6Lom43sHNZs$Y zzLlV@nYyhGUu;{E>AEeDmG-cOH~L7dwGf$X_MGShUY*4Kh9cgz_r!iQJ2~<^)`aEU z+AOC*fKaQ)k)ifFGH6ZN9!wA{3<7;G3OD1iW-^Dwe*Q6CJR(H-!ZXIeWRNvU2Z2Q| z4U=6{K3?<3P;kBP$_Jdm?Kk<%xY`6gjN+>SD3<_crXvVqkQ?BeR#cVK)QL z5&5uB>^kTV{VD`{if9Q7LJv|%=M5*B_)hgcMhO<@OO>A9+VbT`aDo~|=KG|25+-Mcr=DNz7 zzN#D%tuiuNg?{^9340~lflmSFYy;D79jY-v&S^D5obOwN(Gr*H0RIFyRtNeI#or`< zS*v=Gg0SHuh(%m$czm;BLtCxx#Y$;P;G6n_&(ZK#Md5Gn3m$G{K{|?E#@*hyd!fcI z#fnNm^o*kOF)+$HhLtHbT+{-+_^NsUI1S*Kdw6eaP+S6YKLA|$j>bZea8`!L1slxA zT^kkK4pS;ZFMd+-5pVbSQ;N>?+sml`|^i>l^A8V1Z2s*2quDF-Qypjmf4AI=}Iqj@i#|9xstX2!dEx z+DW$2E4d*ITK;&NFUof-y|yBO^_O#=vC{hP7R4k zWl2i=gVdEG3Vl;{p(ZF)SctTK^~U^TEel7phPf;;<=K?M$x=QrraZf_zQKQnkd_%} z8HmJJnaG#Q+00T8WHCW6lAoU`6$-U~G84|fz*ag?^mu22sb=H662Bu)!*-=uq$*D* zB_BlktKz!~65kK7*3f*f{4Zi%KLgaFBm_@h}6LS%U(CDANJDBd;`&7#bO zvNIy%qFG+a%8Fz~vxZ2PC(!9hTlQ@k{0y-P&?I}E!H!4{pAx9=rI$@ty-ZiVG+ZJB ziLDSVrxQsB@A@_cU+H>(9rLGvrz&6gsapVzg~8{BZ4K@UHg&DH-oH=3HBb9SGF|Up z5vircskQHdX%IGTaVpajHYk^ikUcm!k&J7~&Y){pvW5gF!nuhuZ*XES^AYf{7BxIX zc6iwSi~^OLCV7D^qnM#vAAK~}Who!^Es^@BY?-?HjU_pzQnu@jCdWu6d80`HmGm1+ zG7acd*BedRGKgQ?L4^P{c5xs4D4P2Jh#zAPPr#3pgkIr?_qqi9INMZm^Wz|?B>bpF zCEZ_-0d@1^Wvnc^dwfYRrog(0Z1(zcb0rjoWTu%$GmuNqJ{rN0$Wq4dNk zr5g;Wo6=hZRC=-(ScOuo9J$nB;A1DYi?W_E@evbx&DKxgFGa9HSiSP+Frw!GWaEOh znIiWfQ|yaf%0ncjJ5A|Trql_brF}#FhcC=i$MaJS)hcKZd9cScvcsUc(4g6Yl}+0Y zny9a%2)6Xm!cDNqv7bK51hsmFb@kWd?(e}p`|Cf%>F)`L>i$l3_4l{PjO{N*;9A}+PpsJ4dey=1 zx+yKHl%|r{`TA9lVS6cg_53@Wqw@1H{AAWMuu5>vfMG>-d{50fQrCPDB}(AF2{@Q_ z!TJJNpn*T}?^n`p*#Uk#@V~lmOX(YT{nkqL`Uivkjgz6+S`pd zi_I;b&7F)(3N#?*3pp~Jcd>t4HG%=8m&WSu@ZbS_GYts7kpM3Z+Y)RhlO*eB%-W{w z{Pk@l_;e^gIDi=o`%zwF7OqEhqICHzKxj>-^7PWV_Qwu)f)Sy!_aPUK_0sy?DYaD&@jN&){!xAP%JH*TMj)G>I^3p zc4TwQpv|3wk{TFZzzpHpHG4s=;n`pRrFj;K^6U}<#PY0~S%zmnMxA(`L5W)7dYn@U z&pvOD@=WqH&nkc9@XQA!v0a%AW}wRsX?!ZAtEXAIm~S2u<{HGhTRdxR{T3`GJyr%UP&ZxwK+UNhGxi>Ye4kl*uZG&E(Z=Hf~@o>m=@4FQIf7Dy>>^Fy%(6R*2nRO zYYjk0vIJAzS#chRXoReBcDp!Z(w41?!X6$EdqpjXv+&R*@!O2hDBlz}m<#1u0CUFY zesm}}ux*|O{$o6F3UT7_TO{{J0Gr^hF;E=4s5pjQfN-c&v03MvZln_xM1sz|iMo7` zuRQXk{&;E*1u#VeY|{XwH*Hx!9`Pfy`@wfX6)-%W?IP78smL4zqlVx2vTzFq3k!8S zrHQ)&Q00McirjWS7&{smHR<=i1>orHzL9ZSMwgt()?%khF0+hGRI_fJOrSncuO%JN zw?<`Rt&xezKZH#D2Af%oy6DKCtKY2fPzUgtxqBp#Cz(V_ER~G0O)^wo$6B#e-pMRO zEqg+(3H&oue8dM${rR*diAl;3l>VNE~7d*H$1f^^O?AC z%^6FaJHrrtGO4n(cj1HsZmOf8GmX`f03z)XD?;52HLIY21TH(r^Acz%cYbR>w(z|m znwwpyev5CW2rg)OzvpR~P(tuvs-W~F9Ls*nVUXQ6;?J7EO$}O!pV4RsseJ``?fAfc zaxrna&(pP69E^WwJRsq@p)e@3uM_58+v!?Ife9R*RzSgHlos-VEuG>MnbzKh_f>Yu zE48p`A82=uv%3~;*Yz;Sojki)a}GR6HW)+-+GQt!rc^kgjFswpG&TlO=kOZ??>=cC ze2w0V>_?r2rVdeY{DRtR25vJR64@fW;OGlzIT|MDoT>N87HNu$BMfB8wbL6wJP>LefXJBS-#l@YH z%X)_#S8~i3#poKHDa56WeM}?a6eS6JIGQzS0z3X=1d}i1(qm3Qf5g7V@-hG#&Cv&sV*GYlr3EsaOm3bw)CQ9N< zj>=3Jd-*6h27)E_67I|dv6o9fM4vT;tm)h&C}Rtkw}QS+s!$>;8)M@xe+8eHDNT1@ z4Bt*3hgjN2+~t{S5zyTI(MK2&9FlDe`8LTMbibEyB^I@4B<1rMnwUt+;B2sU zKW@0MqzJ@EQvORCibhgO@Y)u*sqi`gz5tw|dQK$e*sIh)7Hx1p(O>)px1vg)k(7r+ zm_!KH0`cRqb@sX6z5VHbWs7B5eF8K>!AXdC%fLb|OO~@9G#%J&A z(ZCJ&SCOA6T=F`zEF)YJM7_#-AAN(JN4K3vu1rvk#D+^g3-r>Tp5cjg*2`Z0&_)b={tPa55M#mW5#2(ThTsaBTl4R}mv9ns#m=1gsKQ5aQX*{WHL5U27IJkW0852CZoS^b#*)bX2&c4z5&E~> z$2bM5Y;9cJcqRuIIZntSA`NLVNHn4x{Nh*V@`;F@^2}?>#v!8Fb3nWHhBfQo#fnC> z1xLlB_6NvIdpJ9Fe3IJuNx9Pc=n%=IPqpq?1$Nl@!|LEfLv2qsthcs9)NeVF>2y)f zI7rqd9{@sm{W-L&*~=#*mH{U)B!WfT|IVULzV4p>B&xCzL(1zJj#u>WBPfP@*-8z5GSs;xRMeugijfs8YH4kkMl;eL z$v!-C9FW6dg5#b~I8Kk)pUewRJRFBPpS&ww*PFz)0%pBehg&Vuz1-nIr53|6w?pgQ zHxv$}QJ`0lHev#cvs*9cjr42kWiF$@Ob;sf4Dcj!3&7R6AyTotx??wsBIH#>c;(x3 zhO%e5@yp;)F5lAd7P-Eh@tHbj>1%0{a~ORwi!+d zj(SqHRqEQy?gBlI_w7k05_sR(R*ZK?)F~I!Uc5Ws1)`qOy7caF3Eq!r-JANVk~ms- zYF||nN9!KfSC##V*8M>-XD1(k&_}fH{m|`kY>2v65=84>-xqw2HjrJ>x?k%H-nee| zD_Zw4ZTank@20nC-30d{7#W-|f;*d2=)Ft8JH)?>Z0XRrOcr$GL_T`_*!FcS%upV| ztpkfXD3}X}W2PX;T)Wk|J3Hm;lw)cMf7BMtf)di2Vjv$C!l3%*U=CE$&R|X|rnC6z z^@DfHK#VyHtovR_-a(?GQFRE!a_Bjij`?TzzP-4`ZBz;db<5H>SoCXz` zYEU|nDAXAO<>(y;3VH`GO4!IC9f|je;0yHgG*J$hZo*O`R6x1Fy4cNpzB~g=`~g}L zn>m>81-~!}6$%$m&8$tUHz~J0k1?B2*1ToQ!Tcf(Tiu8x~b~$fn6M{>R zhvvpT)|H{6l^XOJqAyz6hFycu_?uH;MraV7btke2GG2G^bELTyMnk{hc{p`5Le!l# z;PlI*!_?SX!=+VP)YTtT=vp5Z*R!BGeX{Cw1K$=1v=3vOhxLPexeM&m(Zn5XDi6Q>lkN`oz!1;%uA)7rXuT}G50FriT#78nc2?iVOl;NzmD$lPx1Y(isUu^17tEvpDsCdg!VJnfqNC2>y&;)9>o8%} z3_~*lpMfGAGuKyBvFh327$A(X)8bx;2|&x1(xbC%WI;6eYCa6xIT+a(`zmIe)(S^; zRPIlscaKT|mQZHoF?t?ADK8QN(L4+(CqX+WKcA0;XC)odWH(}L5Zr+A7tzPJ$Gbd5 zX4wuLHPT2z<(p0>=0PD*#0(gN%t zq!dwlEt*Z!n$^>4U~jbmP94qSBH9JAD)T zW&VUl)x$tVD8qN(F&u`y0V|y&&=4xZRN2Aa9>Lx+B{Kaxv;*{bP2nE2Vl5P->6J4QH-Ue8Bq~L53Y7ze-x3xOHxj=> zf8s}iel_<e35k_5qr;K7;%fIu{0Lo(js&FB6@frm?RiH}+5Tn+0QvI}Yg}}Ku>&x@aYF-9 z8^Hm_*Q28zToDcBGu%kkerw<27*@x|F}QYK4}(zXaN`pArAq2k!~p>beb6nbvjkV& zDpYoMZ6!=3*tPXIfBgI+t)a1I>=pgv0T*zZMZKY~hW!OFoEFiXtc#=PaItD~(&v=y z{dn@#r=PjyAV%fhf$j_cH{!>|@w~n9_c6SxR>>Z`QXWG};a3JnTgp7(&zCw@h*w_P zxRcm)(=Q|C=7}(7z0uR=B?G7XAevkzitDT^3&3HY7y>j|KEXCYR$MHa(EIW-6c#$m z?1MmRZo&XoH^l%1PF7WuIVzt)8*J2SqXEAr#u zXuTFVF=FWa2;GTk&lUOcG=QDM;~lk`~|&6ek_P@a+zu}>NGHsAH~w1 z_~FLJSDF!D$wYpf9<4Mmz7n6bjLt<{GVX&9enWA>$@xA+ew?Q_-uvJ^=qK_+=>?e~ zGBsYum?d~B+pmu%aptLPEyrlhBI`iEkqkKQfaTfiv)q3`+%AZL3;<9wpAi5_^!kZ0 zCfj8_<9-G@6;yl#z;AHO=tKalW5PrL+|EQl5dhC%8*pGE0O*_XhUzf6aZauxcDN?Q zT+F@|y%P2FpZzTN_EGFdQF_?7$7LoQiS3mTzlXahUq*OZi_0%8A*9%+JOKF@s1~&q z3;W(TDsTx-q)`<1!IX7eBb!tvja!}_N5VGY!9`h6sX2d*jU02aMm_!^Mi`2>5Nj`m z245M>{~M6-iGo<(h*}QZW3Il7P1L)zo#U*s@zRz9%#O58InO0+{l4IlsjM&h3aSqvwC1 z#LJfvb+!ZXTnH*2%;B*DK;SkT@;Rx{bp?qMW^= zYmcH>y7mnaD~MgT2@9Q$9RXR??;_gtK0C(aT=7ss4s|Hj0ET>E>%nElWtW`Fi9_qL zQ{F&M32{FrsP$y*#5HX{MJL$*+ob=`N&nZfOp|$6jwW+09w{95-Qntg*V(!VZo&o$ zXK<$Z?@bZH85-s3PxRGd=;+u5U5y6)OU6P&aKi&=Htc)S6kUi;i~d;YBIgE`Np}&P zA-)H~HsOJBhpASDzB3nNTmK$zL!8UKFnEN6dKvHsKw8k=8TPGkbtT2nyMi81-}10L zp4g*(pHxea{XutjIiD2fTjr{~{VZLy44ZvSLQvC8YV;0%kuoe@?>LwXy7bUPwfUC1 zaNTQgEmdA|cHxH#i&`yr1w+V}+C2P|4TX~>!=~|XI zqU&chYbOU|DYT3Al6RHF#YzskBxh>oc|k+m3%!`E@QHPXQ|lo{U^-tDM}bY}Ylwp{ zQ9@lqS%GQcf*IBvFwb?szN}YEA%HF>wiIq5$zyfI@VA&Smcjxi`qACL%m$M?^b-Q~ znW1?y%QpMNq;2*`FkPIro(`p$wH{6zHKvK8(i$pfN zMD;;0G%vv5=jg?~Ev0f4rLlw5g33y;HYS#AIh=x#w^PB4{fH$y6QWR%};e{A`W_bt1MxD0w83&4F z91u%JcpXc&8$X?~IK>bJX!NFy*;sy-h1Xk-BqYt ztp~sf3Nu73!ZyytP-q=6Nj106tIm2bNn!)u6mznc z1dw*|BIoHtI`xELW07Qlv&K*oSs!{ZvwuDSC&=~u+6vw?S<0rn_H53IU_!nN* zGi17HkkL)pfkoZp(fWna`k(oF26W%zs-JZ?-}r%`qVqT%C9X}qctnxytk1JN`pqTm z2mIl@@*DXpGTpufyG!0M0gzO9Z#{U{fV?LHDtNlbolBVilw9GswytNU&P zr{-Q-m>%J=2JY7W!qz@Uh2DB}LZa5zAk(xq z9+mN^Lis1HX5vXik;l-?&0F8b1=(O-XK+bZR-zfSh7yeP%ff!F5@M?O#7MvtE5uc@e-Ur;iqvP^2IKZPj&5Os3BDW38p zQal?_m-R|@y|X9JVArg&1r>fj>U(R;=K3qDtGuTTtv$_~<-cxWnRjTZcV1=5{961N z<}LAiM=c(@*qepiIoJ8iYKMJ+y51{^ySm2fFR!b*rnYF9HM6XwbVPMk<#n-yRIu?8 zY|mR#Suww=taPL|zpSLvE1>i1N@_}~{AFde-Z3tq1!Yx!(pytk<*!&!Hj@3ERlT6h zpsw|n)RcLvuPv)#7o{^Jy*brYwH2kvs;ebCDoanR^^O=(yRfpt57Z;(RaBOF{ng%@ zveLS_4kmAH#kW9NRjIeO2*~l3o7P%%gag@dKZ)}sIIv#hK@xw)#!+z8d_^v zF-dP$O<8SqT@8>6^EnQ~y%nV(apXu0fHkt#U*j*CV~w0&?YFMQXjRu-a6$33;)<%; zvKoJJN!?=h6T|97_t7v|S5oCInNwR`S%+4^>}r2G`lknaL}giRt+)2N1#_w^t&yb_ zwF|3js|5MTg_VA5ZNZdF`o_6c4lJl$3fGl*|Xm ztLhfaDXSS~35fUXvqsFR@H>Dy7bEGfEE`c)Ra)V~q6;AmwG@8{gu$;$s=O0sPV-Kf znAan}Y;oD#I*bSeBTKd=pcI_at z!^){%cwJ4!{BplHYwj>FYK%FA9yvm!4iBw$)nJO7Hp|a8|?bSlOAxzg|mJJ#-vkXE3-7=?6 z^a6#vuC~luQRUTQ%A7eBRV9!$Oyvc&!@Y|t{N)rheplD|2Q8>Bt(aFaw}c3W%cNUa zRzrmYIapXz4RZ0rUyi8?$pn(h%IZa&d~>TYMyymjh%9#xGXQ%&h<{b!do!K_D=8>Oqns$J7IdRH)qE5 zf|+>}eFZaS&hlP$)r47qKkYOY4Vp0h3a?$5KhvHy%M0kdY57z0fCETpPMBVhXU`h$ z&6}Px)t8$$ee!TGPD}F77z+Oau<$zBhYwB?Ctb98sk3Z}}8(p6; z^NQhQ18~l=FZBTkg@bY@Oq(#-p5@KzhZ7iq9N$cP8YxBhXZa@1D#$DF71-X%GiKz@ z8U)0%?3tJ4<=C^vd8f`G$0vDxv+UvC+zAB}q+y@{hfoaIiN0BR!mGUL1@_FDzWjo` z8PkUinlj^ZFatDBK-FAf>Wu05l2M;A^9mv*4}|B#y_Zk1F+v#G>55Ym$c$MKhn#{z zE-V4KRj$R-P7*8IuOh^5skcGsy0dgRG&ogDhWd$^5blyhCff zSB|*$vLgKbnk*t%u*;aD=BO=z)x(77!Mt4ltoA~YEv)kwInbPXBQCoDGphn-hSA*> zRr9K)bK*<|tYj&-I?oTy%l5TCOQ8Tj-r%Sv?14j9Pz{E`lz^OvK%wN$B}wbs2>k>XP7 zN)`RAMWybwmRhxzT0e`H`nOiCHUHna%X{~}W!`LwVhzlkdH39VwtMcm>w6D{m$%kq zEC6DZ55pP3O`rv@HqL9t6lZ3LHl`H?5a|)GMWjdX22w&2M0VZ{%Kn`=TYtJ_V-PP5 zDhZftB?2~l3Wignyv2tasDnVUSjWBO>Q+0ys9N6ZR*tV2d zr;&N@0!E1ymDNcMQ){7ithx>Z&}zh5)L?VdBFKB%NoCDtZDq+aE`Pd>hYXek?4cdBGI#EMxw9bL)TuP`=@)Sd*#*B4mvRsU2}3I`V`<4(Dw5Y znqy$5gP|+NbDG_S7vh16@WZpQsv+mheA=VWndbqwZ4F)#`)%-PfKM)pM7_O@(fsq+ z*2cNXrBy7hUz~pIoLT74%3=)N>?v~qzdnmbG`uIDItAC5*B{#DXnOq0CHTGIlh5#i z493dwjCOhs+?a5C`%J*Q0C(Wn=Vq)3Y`{9uxmfnu0=T9}d;3-#_k9LOes&;=+uML2c02fwbB?NF%ZF~DF zz$UwY!L1Ktm~5HS2h_zB=~fVTiH1biIui67$*JHR>D!7k9_VZa)|h1VlL z;46UF0xrGJ`sje`_P^6>$9>s8_(UO^_3CG^BO4fq7$4S;>Nx3_Nty!^@b_BQ~dPs5)Mgg(#0p8)rJ9{!Dk z(8Yk40oJ_)KLC9Hw`d=Lt9}PR2ORUq_Vy{rKO3+Hu>5uS9pFuXw*l@1+zxocF4zwV(^(d-#JcE9Mi3y#|tO`78-1JYXJselH4>c!zp zu=p55dJR64?hHr2>ywB0ti@;dJ>lpOXC7P={x*CjUJ;J|$p^n3>2Lia96g=z_x~&s zRdPJ58;)Lp--a%@CVVmQMbBb=$p=3Z z__Kf?>Vt0p{HTbA8HR2K;5P|9^=8hi3U0 z%4`Du@z=xAGoA8Hy(oM!(ul`%$P@c>IC`EBk3GO&3w#x9Vd#kbF?@P~&hU4_(IZpv zCy1pOyyMXtr z>sNrE^nri*kAQCh-m5&>p)ZUx>Em$pRY3f=+x>Lg*5yF-`79hg0%#+TtnYp^CF_eh`KeZ7$XPLB?>ovS=Hzdb%$g_Hr%yXwZ57oy9L+qTY=~NUvcB-0e?VoBs$$k zza;PrfFI_8k0EUX@aF?x>BMXGd_VHMi99Db^JxA?OJnQ*W;2VG+?1L}F z`2KR>hxp*jfxioQ+AIt2a@%1c@WaPMq9c6DuL6D!@P7QS1wIKpJq95Bshj>*;4dB< ziQ?h%p8CBC{Nup;$^R+vZvnrV%E#_>^;3nIuWTrZL}xnbOB=_KJ{fu5KpvM2T0PMF zBLNJvj6@p%^)W7$E63*=AKZN4CLJl{vdW_eCTXI z?*a#XZG7@L@@zTHKgR3=emC$#0lj3TR|wF0o!?lJ&Y94fo*$l`rg76`tof0S;9=Pw zKPiUQApM?W{qbvnf9$wObR+V5mA?h}hU2~QF_d{6_$><}Q98?Pl-GQg`mv9`;q9{| zV-)s1cnZ#7IAxIaJRJD0Q~mMNf&UQrCC>7=Ci->2SDg@vUgm+1A#E-2?*acy^aq9x z+8B?<+*h0xiGJOK2JzSd{M#w;yMezc9*NHKDc=+J+XMW$uvPd!rY{nGde7wIN{JtM zml2}~KNI*}Rgvh=s64JMKY$HmxNHEP*57V+;X z1HSL_Nc2qnHe}Fve1JTwk!O-K53WfMdV$rwzz_AomjXXz71kYn@biGb5O}Y-TMT8A z!1uf$_4w>+M5KqxF$!IdlzwO{*(8fBcB(Hz4j%T{LKT z>F<3JyPs){L@y=$`EL9q;O93>{6;r^KJc{eidVsy^?+-#@e1H+P1Xxf@tXb+lYRS# z$tXLWGO4u%{G@W__^bu42GEI{kEGqeHF@Bue^_v_8%J63DuAASAa7A*G@Ay9>)v;U zUPnv)&;E7)?8UC?J&z|IR1x`Qh^>yS58-LA^z(NinY;cssD>xPkqr^HKJpZrA(7k< z$ipJ@*@=j&xb9K+Zo!*f*r#1YnQ2omEBIk|_OF7-TV2?dT_U%2VK;W6->-LxY>Toj z;m9Kqc3~v);|RMdLMi|1R*vrnq7jt3q&s~-(p``$D!v%C_*f|NQi#158o}643nC8` zuonyP^Rh0HA9Z2BpgxjhdNuT1Xfx;GzNQS(lE{&a>Xv>NMdq*u`P)io2ZeeTMoL4c zbU%YN0twF2h69VB?5UAgL#!3)8$yv=L+ttxU0+gw1khytLi?9Qszc|8y2CH8BkRfH zz|9C%994vd85;Udh`m9$H3cgf`%{<5jo~iWgd?|i4Shcnxw31QOS?uMkFqzqMy~G0 zuIv`s+>Jff?MBeS|8FW;N_T}`M3p=fiTo+T)^!E3_O6ji&G+Two+t*!K?xUXr*p+ z86fVudw}zqhwxPf7kg1zmRH^A0|r;M4uP;b?z+M&eV3 z&x!afz-KW&=i;*tpKI{hh|h!gJcZ9reBQz56MVW~j`H}7#HS3O6Y*Jq&tiPe#b+Hp z*Wj}ep9k@I3ZI?$yo1jt_;mjs%HuNnJsB}T-CPf1kKu{+8$ zVe|w_+gkOswyY!K8xP;|^lj6pbdnJCWgpUCdotGtiN5an}KDDL4} z5%3m3jAYnTfQJFT2Y4Fb6zrLizB2(y-_?L)0XGAZp05Iuo@#Hc;$A^_79i1G14wi? z0utS40EzC<`$V}hfKS3JKe`|LHb|fMfVdv`khnemO_lHS_@Nza2H7W$V1Qofmhl&=Ml^4$tZ`91|CI}Le6li`Q17|s)s88 zsU98&B){vkP2?X6Ncm?2QvOwdlz$B%<-Zq@@^^hy*u57Z;rjv-{zO1(uV(|2oGpMP z=LSHM^C>`*Gxk_GItXwwAmy74Ncob0ly4&-4?ExgYCqFLgWd$JB%VmIM|667HYclAo05i5ZyZ40eC!MuU`xPBLPW|GC<-}3rKvf03`a? z022KjfJDD=yP#JBNc0u}620qW`aLrJRhb@pQsgfMr2Ji2iN9CkUy=CtC4S0pMEMf|seA(<$#pRx?o?vi01pRz8<6a| z2axPJ|--LAH{}v#{m!8jK{~WLh@C3jufMtO10g`?D zz7Xc?{bhi3T_dm6zP#FhpZ>D&r>g;p?!$mYH}*S0w-#_LuCD?l`R)Rwxb`++3^4kN zxSkA1^>+dw)$;;CTC2Yrko0>HkjlRV_zK{r-wXMk0VMn$K*D$5De8M6AknJ=BznsL z2LoOW$ms!cdVu5~>b!tD7ohh4-*{Efc?*!rMgJ(u4FM$j!vQJ%M44U#I0x7F0+Kym z1tfb^ye90i25<(hp8;$DEPFl7_bo04Bz@Jn0d+P&odNi4m!LQFFM{61fK+cg0I6K} zw*;Nj0O@)IAla$mui@xazu@D0FHlKT+at2`5pu$dhGuMegPomKOd0rZvqlt zojFkF3SNCz_|?JhiTve&l>a(F%D)ScDWBxmV=%Cx9eRDHHpIX91F&=gaGj@_Gm0G^FdeD_{Uf|xOa~->O@Nhv&jFJE9gMRNKuVOFMy)_ z@6`gD&n3$Wn3(_3d4X?qML%97_9^-tF7{K$Na&pBO-FhUP?`rA0bC&A*?<(clM=3# z@LGw#39vu#TP1uMko5f&kouR>;i9}cf3OMHG(Or2SOoYcAhrA55`G9s{q<*n6es$O zi16{GnkPBuM{4}1=1I=^k(w7d=R<0IsOCijw}}2k&4(s|FX=rKkm`LIAdPeU#y>&h z9=~y8(0J%U@Er=iuK|*s)Hw}x9z&hGQ0FURqlA4+0LgC`0#dtN3rKcd4@l#n#{g;k zsm@)f^A+kGg*q!S9Oo5i+@Q`ysPhl%oP#>gpw2C*^9kx4f;w-Y&K0Qh1L~ZBIt!ro z`_;a_+Pep9{&yL^3)t;5x=8v+UHmM`Df3L@bwkvxYQ7#ce|FBB?*bk2gSP<54}#{=YTZJuSEzLj=X_bs zlht}g`5Y1Vl7M8-%jNYG^7;)xYJUgJ6?zu}lD~}yr2XQ7Ul;y%E+E-u4ItTV10c2M zZGhCCcLS2WJ^&tOOa<0CbmYCt}!CpC^*Cd=OnNby0{lXHF7Szl^B*16v6>`zobqT;jaPn`XT zv;R>2hKlE^|8VvjA3|;#M~-O|_CF4g?7R?=^sEIWyQp!b8aG}o^KSyA@!QLQG=A%! z6y?=^gmZm4)AhJg(4&5~43OIKLP>uaAgyO?m-uHSevibf^F!*KkU9^P#F-w_OP&2u zXMA=do#xqnRtUc;1EjceEg;2}HvuU=#8!%U(Ev!-8v$wlec`#H+--nVuKRhS+-$%y zT(1KpJ8c0R4EVCVW;i26*Xk^hIy2PKaa^qf?fO=P&*Ll37xLEtlKf8qlHTf!k~)W^ z&hw~qJIKQSv2321!RQ6}14dw5a-+w^dVHRBfbN<1|u)|6Pz-qRCmuuGjx zux{HzOx~tkR>q%v#765$^spZ`OHbjCFPclq&3ZC_R1trA&U!uBzJs=n-3F4ZIY#UAQU}u3O9czVG;w$zLP=8)n?I0QIyw-FDnbdJ`K#f+Rohfe}f2Xndc(2 z=0S#tZ5|(mmHWVj*eRafR zfAIXDx%^J>k*@lUXHwKr!9PG*M+G~X*)l#CoLQ^2-5KRR{8w4)--4oP>#!k{%=fFz zMl~A-a@Dhe>RU9>i0;C+$zy4y zP@j*2wxXcm&L5&tR>o7`G_7L#<uOpl+S-meVtarowSo?R(J-#M)^M)& za|&20s~&SqIX%TkmZzU_JQJ@z*~XJATy!Z12(llUVyDv8z_FLpFX-r3dSWru5tDT- z%gXFtWm-^Htxu`WAn$d^tNFd5S-B~Ufn$FSVq(kQc}g``%_)ROwVeV=nm!)USUh|xf3u;s4(6z$(!ILs>1M?I5O zNzpINCH=2K}aEtAzKCCxD6KiQdt!WbLOhE|57=`4&R^g&Ntx$LMskAoehb z&A>xy6KK+yz6%Ma@u&Z_u?f!@Rx(1S#n~SvI#*_*%wcYr#)<5ZkJ$4K7;i=B!JL7W-`0<&_3#we8$wY7r@p zrJ=+kJjA-Zt?HJ}XqFj3hO!z1@?BzMSMz zT1WChu3|5A*RR;Vzx8r#okFJMP3NAQNBVrIcB3ajW0}h(v4IV;$Xgx2z_dy6%U(7& zgv>w%Zk6*uQuAQf7{*xrc8upTsci2po$HlCa%zzYMYVwTt4`EF4OB+4PjZr6(ZPUc zTz4=s-dc26#Hk6;wwt1%weyX zm6@p}s5;L9jWnuLZz_&D)lsf0)sb?pE4YI_moo)#p5~IJj zC!C|pMHT7>fVDjn^_iERKgeL1fJ_0)Y>Ug4@AV*&hTEiCu+Pj}y<@=^hbEcPRKBw_ zM=In!|NcA-!X4;vJncdS1?50ayBl`#+@mpaxO~XK@^;Ls!B%%7BTFCw=|*cDMA9GY zH&(8Q^F5f2Ad%7&ZJLh2Wg}eT+9(;cxTT*rEN$ljUE@MGi;W0k!uI_`XK12a1?NuA z2x2JR$YD2`>e5H1`-b^%f}L)fU^=RS-rSLbS_WaSWFep`jqW&#C-w-PyflaM zR%luPBArtAJUX4%S=^MF5kY>P0Z-3vCw-sv9sv9;hkBAHB3{eQQ%0kFx|N&<6Y#1& z13XnNjMlfIEe4uht+ec70mh3z$iYOskA6cDP-{A*g)VnsJW>TcmWGDCE-O&w$&t9Z z2(lz^)OpQ4;7Lwx-?_}75QyR0Tuypc7vpYn#6ZIx8%iOcoA5`d!u578Su1~IH zr)E{$8Y8r#xYjU?)q8zMyaq2};%C~_Ubg#aG#(lIV#$jNbyQsgh$H*YIYaJM)? zQOc;DiOlQ=D6HAQwLm0SMeM1RW1ws!T%Kj4e22*oI7GLLq^73A#LleC^L2wx)ScJV z;cw{;Sj^gOm0?+rB)v7-c~hGQWHs@Wl4mD)3zEaF4&@jbRV>-xq4I!0`TKbEg={Wx-kA7CL zlJ`u}6vic&Lhwpe;bJCAn?h+W<{qgj8jcZ~N>0U-?yO-eh@DciLpj~uIh^#G_&;vT zj=PD~nwPPme-ANCG0JK6C7!HcXW%-eHTAy4QFl7ZRew4X^+%I%KFT~F3@vfYF3;@N za$<%j%XOY!mOAVo;Hn2~-3UPzDl4<5eh2L7eBnnO!=?qXHToY%{TMixt_D_jhbHi} z>?fylvi}1Eqgaj%*~ZRQ&(ey$4#v7y7+M9IO7jc$j{v_gDCcOevNELsT;m9nvpF`j zXFX`-mJ^?ub`fj+;tCYuhB8JRHhGt=Y!nYLSi`VrJ!-PgbBAOY=R=c~X&kM;*R50d zzEPE_%2+DRMH#nwGzKpFXgHUFF60u_XmgX4{eVWw;aD0bKmgv6ZzjHJb>tf1+*tm# zlUX{3fP?;Din>+bwg5*52MV0O5@>3$8^D2b3^s5pudOhI-B{}CPpWY!E6MIQL z-jv==5f%?U;3|Hp3=zW(t|=RUBI0mGm7JP32C$bvQ*NiUxO{Q-*psTpYAYMsItLnKC6NktBlvbc*Z0BI_66MjXJ4@WK7l3FaNbVG>LMYGy^oaf(=O_$eH-Dbe;cJd zpiY;j6ZqZOnf&xnTftrj>udreZnAEr2kMmm+gU%hIWd}QAhf$)f%%CK#uV>U+~UfO#CP3^#W6|hl>e9_^JJIPiOjT~ zsRUhzaxxSlQT}32Q>uMSa9Npl!TNkAA9{!6#8DU4_S(&CkrPMy3D{kn)P9yGVnLW>pzxTN? zcC7GLuwO$A9yR1(v#PRs$@0q9n#=~W@hWrZVg$CqA*x`$IH9QXRSGSW9?1|h&O-?= zq5KE8RYA)Y2D5C!WZ-f|9yq`sw?cKpRH+AWd0^Tp>*9`U+-FkQNtGzFQ6Pu2DI#kUjitvSw`lhx-D;^fRbOmeAnoi5o zwmLkfwt5LG4Ht;#IrC$+wzFV31B|wapk{9vs#rfO*k6%J54PfQ&e<;rI|f3ElWP#9 z5a}!(sJvOxMpPXh5m7a@ALhg*AdKcj8yb8c8e|t4bK=~=TKx`MWf~2?$odTI>Q_s9 zspr{|qJq^xIX&j7ib&P6)!g?1RW=^4t#4@H(FGGa{yXJxUopw5--;8$nFs#_aC!T=eJsPn@&Aa3S|36y);r*<=SGu6znske`}kEtARFzaUp`wnvF*}E+2rfaF> zRM95TsT7f{q6y5s1L|hrOF6L%aG{)NLzN@CXA{kF;71$1zM2&cd*s@?M}b<06Ssu% zCnf63cGK+~SlMfoO1H6JB3<*ljNIKg16jd711W8gtgp?%O^nM5HovFA*FT5`oSrbq znvSlcT+Xf|(-}DH`5jKLqk{RsV}1zT$@x?FpgP%{I0pEC-uOVXf_=@lpwkXAjT+&c z4jS4{o=zesGq5W`IOUinZ>+R4cB9x9Ws^)tYR3((Fu@H`aHy6-o3aVppWy^PM^z{26pYwXb?yT&@}?%$+q z_WuUX)%zIObVdM10Y@7)aA~kYSNStoAb1d95YCZlKTtJ5XsRT?5CieGHBAVF zDK&P5h`&I8z1z-qF;*WYR^2P@$PC3ZCrZZZs!WMuLcPiNR zAnUaWU}S@h%vKdvdSYJ=&#Z7h&-L>(XdmTiRj2lx%SC#DYIfam(tuAr2tr8*y&!4OUW}8yU z8Sr}w{Jd8Qf(CbrnZw;xat1Q=>gQSAon-OT!QI;esRutw(OmV{9rDMJB~u6DM}}}S z=%R$&dg(y15iqXnpQVU$UkJB@v{WXm>pE7-_N=57B6h4~ryXkUY3b*&N(w#Wk#{h5 z3`LB~3U&@i@i=0nyGENkkY_+NREkYr0e#WjF+EfZUSY-kk*=y06 z4IJ*3cP7iL6opO76|Cn#u{;188I)RrQcgVt@1P;RlmES-WcGEL>rgPrUz+r_a!NKE zR6T|UnfHzkyXpZ>N4a_o9VvTCJqf+#_aS0%Z)p@VdrTdb1^-Vx49{mRf%h8gj2%6Q zj>*&k=t0&+Y&VF>@lr^bEaU6afoH`rENHTS^N5b2XdUkU9Ids#i;|0wp46ZghEuX2S7p&WK<%;qhId6qy60q zT~!(sszJfC<)l&e&J^5(dF$)l{{f|}BeW)|?yf4?)zd13$5N6m)50-UO{9z>ikzbt zQ_0z~e+cZejl7C?o<-_9*2h;q5Bto4Fn;z)9Z@^PI=biF0MRn_L|3?6S&|JA86jLtBaH!)rSO4|K4=B;r06%L7*O#M$P1l(<-QurPdC!Iu&d`!R%=p$)9k>{_adDJ)*#TOxkMw zhRfM0vEK!j4~tjRW7KXpt{DF2O=NhURI;pq9kG9iv41jFi^otV*$n)`qkmef>sr~l z;x{hYCj3;#YEmoSJzdx%8H_&@nmadeX@-w;}O(6zqDg>t4I}Z&oJn+KXne%)h5?N{zZnXDJ!!j z%%6f5O*W?^*{rttG<6c6+rg*PJ>>n4RL-{H!5?*sOOz=##;YOn<9x1GmmjjC+2U32 z>ZKITt!&-is)jPV$7`0K{c`AJyQl zv;!NE_sg4C!&qE&IdA&HtARW5@b>3hzN%yKs$zX)Bf_K_ca3CE?R|A?-Cw`ws|xn3 zVE*#A-k*FGGuDCbrzHUSsZHth(Vb*#?r`r&P8Emd^YZ zg1wkQ-h=)vO{vB&1OLWp&Y z6qWKunhKgVGU7j}^t07FS>?+@YO^BRK*`s6@-v{J!ISpZ@Qt3b=ZBT6zVbs>3=VL6 zxTZ#r&%D}ne)x5$8dmV&ec|Cy!?*s;;GrphmZ$Psc9#YkPOSlI^d8BXo~hLzxK=gV zTLm@#ICs^p9a^gg+?%M$ekjKR=uODSYdhmj69g(zhCNKY{N9Ldg&L#v{8O>bqUDT{lNRnZUcS?$@s{$2**PdzZR!}luR-iJ&)YlPGnOaN#ooBkfvv^dud`S!7JaWkim$cv({L%&S;O%AJBOd_6%y?4%3g+RYv2&q?_GJIOijQWR>oPujjpVZfk9(O%99hhd++U8xo`NoBG|G={I@Be_ zbm*|XPjFhLngX%Ea#3v#X79p@sL6+KEwGYWv>Gi>%;(25(Q5y@g8;j0?`t^xCZFe( z+>QsLWc>D`yg5>y2vx9AVG0WTjEwPgp*%5=(KzQG7Q^0kkd#a16xa7nB7sjd%CC}Q zm|UJ8q8-?c1wOt!KN{?PgA_cL;%PXU(HK&nHu`V1RKUZ9{#(rg2daqJ!w0-+_rKK= zY&Gm)EmGvi3b5|2MAdjHXnshedwDJY0)y%yT}fc`sHS!URGy@F-rtQ z{`}g!H6?F?Z%<+OFShXc8Zn{v%De4#6KuKEcs3+A+j+`~Yku5juN<&kO_oxN!Cx7v zx)LukFz5AX2+wnOG6Pw9w*~ySde&D1JkR4C@TFs;&Mqyvm< zJvGz+RX;*n=O%Hv@18S==l1`_5?Fmxjiw&%saJQ};} zK6~BB97i3rTg+bC`xLP6Y}==Mh&5K?T;sT&A$D4#wW_%-LARB$2P1S}+3hpBu^0@T%K>F*ky9eW+cwFtSr;Hi`#Eu!D;P|XXY9Zu=l`}4+`W`da%&q{C%HuGA}2# za*sgCPO|AJwm1th)mG%0-(WYOxUk5)%BqHhU0c8nY&9KB^VK>2sLOzgTjQ}f`rX8$ z=GK5WFUm^E+RHHd`5EWCsA*}udWGl6FjpRBWqdF98SqgC99`}t>b%a(^Pt9lZJp;l zqgWZZ)z&xFq#hvVs+8KJmUJrEou3ce&%jp5Ae|kWCsv$N%SIJ7)`~QK-*Tb}_XH=}*wrebjfdto_AnCU89JN=NFrYw+hwQWR${vI zIC7|!3k4~q$WB?*oMh8*IhWsd><$IzIdRHzdkBF;@Ab`1@_|ETg)|FE(GIy$96bq7 zbM+%URrVt8z*{iUZ8A2_v6tHc9S0&g9e#J=VFL|eQZ{T04G!xCsdArH@ zSPEmPB901dMHz=7temzHZuZY*XL`gxlU8G&q$8y1oyQOMmC@$DD4k5-QJIV?;tIQJ zN0`A~F~0+ilmUSkbOeIbEQpCaO8#33D~G?SX<&@QZ_XM#L>ep2QZ&Pujxre!{IXFK zqojJyEAO2QMSb=?(6;;O@@ynzPn+@?o+v095qICi0=z*4d3|5g;Tk&1<%BxY)kB;C z-n{J^-fTw|7d0Ej1CA=@bqb)@e0)OD!YGK}umWh(>A%_Z7b zF{q?${zgGZT^qPSmJ}A0JC99p?Jc*CKNUMPs7 zigjIwrBxR?=^XV?MjXYC25;W@WSrHR1k11JpfZ-^M2N!oWu0yY9&LXPwn`6mG+MU; zOfCG~k(jO3(0TklCtLBuyGIuV_>3JS9ll~CT=i?CeEmHRzPjdik<`@0lGe97MQT-> zBiS8UOKaVo^?av@%suh_PGP02gIo6xJUrXV6rIQ!s=VqjNeyl06yy@Bn8#y!ewruJ z+^~B*iDfnl&}C&6!=>R=Dpx#Rf?TF5kWf`I+8X0!HP*Whq*C_f*-*9n?2+t|j%5H( zd;=VUmjScUqd3M(Rj`>OI-JE7V4(*`&e_!nggi7VvVzQ?Q7~ldC@~>29zd`&M{4Fh+=mvMu4A(fl1dCP+1Efo^9a)- zqG=e$Sf&^n#t3Rz<}K_mWJSYN{J_zs;z1Hfb*oTJQ`a?tkoV%*X3Xno?P7<}Hk+W@ z5>5W6S(m5Azr7Q6=ds`eFm%QOTV-n?ZzSna!A7Ju58^|~7}FinEm~H_BgLsGuDONT z3T#?>AF({`B62k`!8R))jkaTxPpu_?0Ix;skEz(Jc58KLUB;%+Pvy2~mm#-1;03iX zv~i2VI#96n!jm)X3wA5XqRs%>=@o1{7qUis`iG6hT@I|ovm7u-`Cy7;Hh~Iu6>??c zUG{T7UIYbh1tf9E{;qQtc4WQBk*#$#I0ACcAdJ#nC0^)Gw8luU1E-73%ecHm@TCFF zY8mDFkJmcB)v^m@6FpO3(^FN}@e?!xD)A1l#Am${{~r>C1DQ8{W_&BFU4Muc+C>FB zxsuo#I}K)fMcD{fZP_S3sSh}FXy?wlBSLh18>$_mQgE39CX ziS_Z#O*n&q=hkXfW@cMT*&KJYiIdAgFSpA>jdY6d{s|ho?-luSw9DZ~`qkc-KtIz_ zo1khofu9fNw4<(lCuK{=K5=@oqT%QlGwyZ8&_s?xFmCxN2s>!#t2{NGE;SpH2-3$vxeWTyY`6pjo@_`$@H-*6nuVd4%!Ug48)#(EEoQ?5k{(tD zE@}0HSu$AIp$x2H`vziTcXC`<3;84=v+CNiQMzMX>WHH=@4UV^(yxN_-ZhZAd-{TC zV0qGG&?Ei0=$7T0?VH zWdnOcOO&^G{7Xxc2VaMOC+OI?;Nd)5Dl1maHsy*A?xR!)xfQK?l#y&@x}3ZZ^Gh*Y z{kemmYwpE<48FSis{*MgiEZ!y&8nnWf_;Z;tL`pM_ihHMWDXWU_t@jIG^;cRHu9c^ zabTrt_?Tm?y3c_yJ4Yjl+a#P8aV2D0wJ^}D=^99Rw>)H{c&G9l@57YryV>}l@T4M? zO*z?DVr40a3Y$28ylsii9WX$DXG0k+<@q86(ZH$ghjgSwcNePg&oOGnFPLbb7$}w$v#Mv zjkj}VX~Vuf%%P+_Y@4Dk)KSZdEK1T=W*p_xagrR=wCaxiu;ZCk(K+*N;G?*9z>S2T zW?^f-IeKJI!`SBLsH|&jJ{jq(HN8TP`$q0TDc0ql}#g8 zwr>_1UW7uvvf48IG`(z3t8B*Ja5^o?yus%mrYf$0XN|m^@iWbFxN^{u?2!G^G8#Yh z!*3(|mRZ0;GhJ>ilcPmEaay9r0!+yL4z|eciT@6Z z<%g)NSI!Sv@$?d}(~U_OOK*qy;n#s`s4#HN-X}P{E3YUCETQb2RucOlty~iil6o83@Qpo}B0M#)2F?M+K#dGN*@H?5OL|Ko zD}}wLGG!#GY3(rwduf|af1sFp++o+2C!*GE62yZ&kTX?2qx+*GqjpTvm`huS&p$(9 zI~?VA{P15m$6{rN7)`^yj*?#!%PP+gQCBp`4_P()RBkqso%xlK{6_W4NZ6HFWm?II zr)u2>U8Qz2+|N;h*O>}syx&SI_8GUq?T-hgWk<&fa6B^2R&+9mOd=~wqNvuzxZ6=q z!zFvC5_Y};tkT~(%xZ9n(VhLQHXPdQ(y!B5&Hzi{3G#t){GQ7{B2_c9>0{cM%y6?l z{k`17&h3gLHcAXF3};)KBQ?|Iz7J}?3W?E;q04qp?tz0NLxT}`te(5M1ko_%o(dY~ zAx_zB;VtJ7P943plQ()LTg$I_Au}G4$HmH^^{tl8?=X}##nFuF(HOJd9Kf{e6yl}S z>o_)RJAsX6{cT{Uf_b(}*`I<&aAe|j{9icMl3^xi&EbM^Jb3XdLzh`IG4uT?c{KD- zQa#~PhBl08tm(E)M#Cs=`cj$}3?AdAX4iweJqu^jh9C8QBrE1PPX8{?JL)rqz? z`@zY{%0&>HZb7g{W~>!dl=}3uO*^xIANV53>`Lj6PH-YhcYxY8Y9)Uh?ZT3d5>dK!c>eeM*xz}l9g#tWr zM?Fb3gTWeJqJxu3H*$MeH(*Myw+>gSR#3tItysvQIu?62qxX{1o(~*#=MhxrsE-)HtV3Z7B!*292EG9 z1Qg;q!oPi$D`~-Ik~n6 zQROf8p`zxv)j6Y~dAv#u!YkORc+8=L79ZNFwrBZ0)V#xbB%u zs>@0;ogXLY$U*OJD9Q&CRh89CmRGi>_ofl&ifG{WQ^(Fa&cNdlGc&65?#m*_qX~nn z1@8n|+Ey1Qv#~Q#T9l9rt$5dkxMu5|C_HJSzJ>J}=_t{PH({_}J5x2H>~E=%C8Hel zR_jG)ro_@6n#bZ(z}T<4vUl-1tc795>hZ#i)<$+ae!?x9>YEm^kMKLu+S=U8jz=bR zlGxEqG~#t8i5jB8z9op@I~=0xJ>LsQ4_F_Lju|tyZDm_cqNQzY{e(#q$0izT$F?Oa zTa#nvvaxl|jft_9OIs5S6UL8CHnxZ?iyG>ysz;9>Ghxicu~kd!8)`-;TN8<~dUAE! zQZ{YY*JH=djg22OZsM4u#<9@(xG@TP^x-0$iSIsOPaphbp$YiHotdm)F}}jx3g%E^ zv;c4YVg=m_5+ZRPC3Y<+qr^y;`lcicM+&CkDjF#`n?SdM830I>RESNeYj`_>ez+Tv zg(6+TYa`LfDfrE53qhVO9bLVRbYFPUpJnPM!o9b4U+tk1v69-LGF3F&P*;Sija z|B+pfA2ljgI;LbyX>5E+$;6V06G~#kTUrySs08L9BVxm+B&zBwn|PiHqf1AyaD8Lt zqQsc$YNcdb0&g~J9^2MhJ+`H?p>b?WqOxIZOLJSYf!@$kKsPhQldSK{7lUV)ySh`I zgsrDY(?MX=PPnbExiuNHlBq%px`i8>n--agDBD)Qs3}ns6D7OKlDt49EGklz)Nr4Mg=EKVuP-dC+@R>{K3aloKN6FET{sq!>4Hqm$$|NKd zkK;~Hm*XbV^?2@cbj=GCmy&%8@WLcq9!oFbDLMRQq9{_PSK>`dCBvVvQ%Kq?l5=E$+ftJ3>Th$%JSkUJoxwvXW9tEjWxJg}=_H zw`29YF)`nCcVW=_C-od z9cqP@9MzrYDMSh!hEmEzN(?Er4V8=9Sjo|X&QPLL$M2*mDHrU9b3!04QjZa-BYA4m z(neNNAySHw(pG2X`GJzVnh9LQF;}!cZrPlrW`8U1o};C?)Y1E0vrqY|@ibU;uj4V96|D zgI<&-R6Av|v?Wq_D=e8UDD|a06!TfhsUoFN(XMPjyJ97CM9~-}TPBz*5{I&Gt_lG1FKixMzfGQO;`VJV#Hdx9$LmXzwR7vjQfNh#F#dE+?@W=qDK zlXVHSjw?jczPwl+ufi)u74FA+P6ux>nW;%sEnUP8I)2}Srcff=PfNylx|SU@xu7N4 zT2s%XM&GOdf;>Hchg+gCQeg+P{SPTU6UFvF<)XetR6x`SQQ`)$a=V)hmk$45+@7gPQrb z(^YLP2aCSVLEZHn)Zfp+;ukqs@-7Dr-8NEz#xWc;&EcT6g@d*qaO{Zx;pw<0!7DNO5vjD_^UaX@_#(>goo~; z#A#1)F#T^F%;<49C7w8fgOg6-U}hT!Cx4fNSsMuqpY~f0zSrkAy88ZG{OSsJ4_#e3 zn1c-`aPWg#4z9YGga7#n2UlaqK*?P;U&+X};!6uBxx8Zxv^+D;u0h z|E(+#6mw%Sz2>ti|J)T;c4PlatW|pBXhTgaW=%KwMqB#qR5^pMO}nJwME@3Yr?5W10f{QtZDw3M8sx>3t(Eo3HnG)O%#$5rU@0qf(1ZvEg*`qwc=qr4 zfGHHkl3EMv@!5G00RyN*LX@G$ze9chiVUHCl-%!5{KQ}H)&z~4FzAxbl6uilJOQ3W zQ!{$E^f4dtMY>CVI{F9mW++DoNMK85FP%ZMK0nwOJ@{$jtU0tb4tYDOL@UTE<}O&e z=RUI!uEG2k6%p#O4+b&&oXXmHz4W*h1C)K{h^ugqKhV`&aTV>q8eBtEexG@vzR#e1 zsNet6EcwvTN&5gJ)B64eb%<2fTQ0cT5;)z(#$;u1dgQ161YfxTbnBvL;Wtnw_SZa%~gH641w}xRhc>m zN1f^@*NU-@J5OLJM zfpa;ZfwkG&9v~K*=GN7;^7=14$Wi|q-f3G6W!C-IW*BuJ5tp*=#g(diaTV>3crJGee0V|eZ8LRE4a{IseRJ9|`Rqe&KKWqrF*YDYATmOOM8Ae8Jpg;+z@P zbCcu7X_Ms{)l=tI;%jQvoRj8O&6pRTR}!B$Eb|1 zHEBj=_c)mz`*C4f8vKRPC4pQM<8vp)*}JwdBoQ01q!7Y%`aSLY-a@7vca#U?8MBZo z?{*(|r0b@R8M9{}DZ|9vC1({i%e zOSa8kv_#Ff&HQ9_*^H!NvC=`j;pvC7jHyip+kY)@BomCIPcvpOp1KVFGcG=E9JXq) zVkvguLj7pgD8BYQ0Pl#c;0)B^C@1X=M0=7tJ7rUauUUjx?05b&ijBQ(NV~;JQ3;Bs z2{)grQ|?EzVHP_!=CXk?O2;_d#|X1enkX6+H%6(;7&MXU$G?OzF6W$-F=s29`#1$L>p84yRN}IWMSJe}xRlKI2O4e4NV!myKw` z(T{%#8*Smdl#T4-BZ-a6LLLlYC5tAD4H`nCdyy-SX~aD|XSPloo-XCLtz>cONAoKd zTf)sQ;LN zq#27bEJNjwr~ho=-)a0q-~5Zkx*ndHduy@AF^kbKt{JC>Q#LrRbOr1V`by2OBhAj4n;b}X5ev}L7g#sHv8j5-~1WRSncNLyI zg1fVQrEubgsCC04dO5_=F+`u_w_DR-+Xg2i@H1~|tZ10FTqn-hMGI|B^ zMc1tG2P45TjoXo&g78_m+y_%ax!R3F@J17KDqM1Kc&H+gnl?I~UMs}3hja;?qSvxj?mW$hA8GpcoulQ|>k6 zy}c$smT@#C8vGz2d)i2hf(mDh<%Y6?zj5wByYLD9<4Wv2cI-z4!?=k~b%grSxBbNm zFE2rAaO}6qI%2bpa7AYul}_xpb7##V(;mREmOT)|FcWKsn2Y0Y?vW}O9>teSkGhmP zQ2MsN*nlnLc&*jc;|`Ig>O^`j?NC!SSeF?ULXA2PT*#XayAM;xaC?*fU3PC#lhH&`mkxx4Af? ziH&f@6C0%>%KpnqzHyFq<)BfMu7ws?^ytYa{gdM3(8=D>&$tmPwEtDWnvQbka7v%u1h*$%3_g8E*G{vjuu}% zoee9zb}r6iyxVQGu?u&bIh>VR{;ZcWiHKA#t36;OU6IBOrfJ(kx@rl zvC(tSEvPLmwgci~G?m3Pl;oaqq-*`U^>S1L{}O9@8;?#qWa#ob;=hhcPftfZ=b#~+ z!cvOGHk5b1KF%SK)AzDbPHbKtsYO0ZNx6Bs{+P_%)ZBD5{nWs@D$u~@=Bf7PqdfsC zE!u$rM)YC^pGJW;TM!1~IM)3v}uu^U3c6hLj2;xAi6(0#ZO)zu| zoS^ArCA*^$qmE40En>HkUE{~o{TTFiJ*`Id3dQ*1WIjPCv9lU;7~Y3t8pBU7sZrH5 z8VwE@emrrAyO$n=mx*mlW^Lk5sl?v1$v8PIKWAQ@jQ~{5n z{0X-9E}~jHr9R1PtJGc?wYXyNgEP8fPlvv>lRAZ)rlGQlPwJ|*xXLbIuiYZG&0`M^ z^^>)$usrwdnk9leW6PE8w~ zch1|68CuuebR^U2OYGd}V$-qd#4KXIQadYa1oX2x(I!i0zk!*dja^4`g$KWJlCKBv zrI8?yJE3Wq*xm=_aYDs(Paoz-76;Ft35$Q$m7bSVK*KAXx^HL*92f_RVx2=%Lsi~v z_}9U7RI>0j;_ESMDL0Q8=~qG19n5#^>~`-a`WZU7svVN$$7NaJF|#0rF(*jvW;Xqi zj`pizTmenPr4ui;>^U&We%52!F})6n&Q@uM%J}gzR`>v!*Q=7XKxO?5tX}IRZdyZ# zg4vl>ttH17aV(MD^fj=RrZcK2Y#>A0$KJ~I6;Jr5ap^PqTTByIF@C{{{kS-z8y&RU z9r%q8tZ?(GvdU67LW84OTRO_s40U8W?NHC}Xoxy0m=86@OpcCuEo$Rjp|l|OgpQ0e zS`*clfB8Z%8{BseEZE*H!)WfsPp!hL_-(Jj_MjU`25gwiy}~`?4PI~1jhB;M14cu6 zv2nsNIkuq-1~eFfY0%wZr?c(yXLe!sT0T!cE+=l0q|Qqozb z8t^Y7?z?Yqaj}u29*=>96y~%F7r3zwsOfh`~^6&M0Me*MG8_>Pl*B+kc zw+#~*`VCR+n|Ap6unOXyCgCgPh3}DM!E*%7LfP!3S;ZZG6?g#2S{=1r-Pl32IxVq- zC=|6<<>?xm>($11+7I#E1p9uIq33{tcOf(Zl`FwCuxi|Ga~ zzPujmzt}@LK_qD6;L`72er#@{bC6+E6Jp_bsuIeqe7R9$Nhc~kc0Gw`R=gmY%K9$h zUgpA;c+qi*rM8SLN!XC-OH$Y=eL-AemGbkV?z4ul3@kE$opu`GR*8WbHpXGYd|R_s6t_qX?j=$Z|f)96tleELZz z#!~i_hQMZTsiU&cJuv*`!5(It@iLAKn5Q+l+Rf+b7x~^}Ny|&V+3f2jpO25Y0ze0B zg^ahl5#E5zZp3UyB4`ZSLuTrSX65KcvT;|@@f>NzcztEV4ydt#=XlhNih7?@3wBjb zaF3Ryg;Ml^yn-x4$v$vQtE(-`KJfF1bS^uk>RfZT5M0wV3L8?@mcn~JmzHhX#Js}T zFR-7_&P+Zd1Jhh`Wbh=}jQ0S>!Wd=^=Cz{>pKUL0rL$N#U~$r;YOIdgWaVZZ*n|3t zWA=+)+pn@;e3t|?$AM{CB}E73E0p&(@PMn9`r4>GwS^oO3!YWzwP&AIB}V`*PCX?c)Jt z1~#C}xgPap#le)_wkf?iLosk!*&;B+26aUl+Q%y}o5qrX`H=HmP44sdn-noW&sOsB zqElD-dQs|Oj^QUcZj3o1hI7Oa*a_vqR6cv*)YSA7K|BJ9uImM|-0663Rfcn#An#tx zMWORZR)?qU$XneAiyg4qqw2H{uMfG~fGv()&nb?qTo}a?QIx{?^u#zKoz}*5z8~LytHB!yt>@f=Oc`O@> zG0LFrWXK_OgwU~!Zr$0inD67#oupQ)*S2suJ$}DYtnq>rb%J#bZHvmZnnI-2Anh$? zE|{jNvuTl(;)!h}pKMwmkdWpSNH#4cg=<`^5D+hw*ZT_w|21V{LwOjVs@6rhq_gGhz&Sl>5H9y|vNY{>zK3AlZo*1|mg)5gxXh~YtjjW!{jF1y6N!=H{eO!?;?rhLa6CWut@j|8~M^d00`ML?>EXn_F3b77{s#7aMjNAsZ8o)pbA} z{|jE0()tm)AEzG)Ux9?fhd+Yvn)+q&B#RbSN6%T>oMeSHlnw8~jkYElSz$t4h1u}k z$lIVYFOiuWCW5?`xlvppbN|bcS?2ClxLoF5v0Ep-Qd~vZ2s-}W*izXVuWf=Th5sxl zLGegaRgz^GwsM2_ZKR(J*fEsP(o zX@jc{+xmaPpE>}Y8kT5^7V#P5+*0v@Rtnljvp?*Y*6&+29ixSC16AE2k zAgYuLRdfcS$egV3&@NPIp?)MA|6)Ze2-^s~npj~~7h4%o*G1P0bX&4{d375rZ0aIh zj*>N(i-doIgz$3lN>mn(6#Z6|qhhSER?>BpD*l8rozvFbikj%!MW`aozzxD}F*-!A z#$<)>hPZ4+BiEx$Yl6T1mle(}5T>MWA#w3!%FreX{XG=olUp_{&Qp`E$!5^H)vnck zgh0)c!G>LGWkLl$U{@f|#H)Y}+ic}oicG)Ug3_{u5+#wT=t-VwWm}S3!A|L8qBiyr z3bsr(H)5B%uvHqA`1d26&>|B45Wk0#Rf`V&J}*H9SYf?1CC^W2*7LPn@XllP!c=zX zj|ZGi1u8-P(A(n+v?1~Yq)lDHsO5zE(Kj1#F=cIN;F&iWnUCP9j_mhQcJib{?=mt^ zK-$z5AkDptNK5*=1$|y*i%|sheG2t%N-U4tZ+9l2!mFKoyIus#-TUvaP;4 zj=)*pv?#0h>0(6c$$}o07$Xt#%E;8ve(<5U5H?;4A)ha1r@IE+Hi{4GQ|M;r%z?P6 zk9@|pmp#Q(rbV4eEqIbk0YO8)u-c>QdA(#u%@kH&W%D+_p2M_}j&W(ABZDeI&zmC) zQ#)g|+gm*&i^<$TxfC?8K^n@ph^to|<+6PXXEv482CLpGY8gxgHH1q&4d<_%mdQ&s z4V?~sQ!TaPAqstuxW6tZ0rSAG6j^Jy(abrEbxlg{t82b_08nFIKjahT!UN1q% zA$crOk8{1Q2d^`yw~EigY6!is0o#yMr^6YM`00xkj=#p#)qd)ts%gjKgGzQ+ zj4Uer%1cLkksGTu_R>vmIv&e)JW}Y0M*=7v=?(7UHSUG)=sFHQM&BP{*Uq}fAe z?KLI5-$SpfRYmpSS9^F8)l_=3;Df(MRdA7|+^_%0s2dSw%??7I$a5s>TInd4W;)Wp z-cF*UTXuz6uQl*j$!Gx>$r&Av3R5v%Z6k+E zZv&e`aeIp&=iqFQ)fXExH^TAU2uBGc9A_J0@J<+kzF6UlKQ@e@kIZ7mg|4!VaOrEK z{FODH(W}=tcEGR{PWxc^%UoT*I)9qfr7u?a(shQqT3>0^tyh|^yoPsaui^aFKgnG0 z>5M4+8VoQOU###~*Bb^Pw;SD2Zr<+K9Sweq8aKXJ;q5mXy6Z6*dOI$4opqE;YaQvY zHyr}716dA{d=d|0M~EPXHzle_elES7o4#1#jW-#38ZpVsRgA60DOH~8wud5xr z4d2c!c>4{h>h?fy`oh}T&6?gAZrJ|l(9%Y@RJ2i2KaW9&;lg(3r2B91xC3wb72^&q z9QVgEk~RK?0=jECRM1f_C3K{}8eVty1~>onH($;eL13PX|1Gmh)gfE(s}m2GC9VR+bWkS&iy4~sK{Sgy<};NBz34n z4Y$j1T7@#bxFp_K*}5dr3L6a!72Qs|Bqb$rEJM~eu|cs=F;6Ll9qX}f-^>OLk%pWk zO*@_qDw0X%CGqBlns{?(hi z*bT4>j1E1?F(;J7+v>1V4}-8lV?yJ(2-8a94b9a{*r4&D<9Nb!aFd*l4jsoi&BTjq zTPkbDu|da%Xqmp?Fw9FS1wtMtQ|3eA<{DJw6e;z>61+lYXJXjr>6V0_z0-xU=#Z16v?;W-DanS+B7cO3jY|L<9x@wmro=7< z8**wNT#Jh;He?Q!Wjzk)%Gi*($Kp49kL|MtKWJC3`&@i=VcmX?>kp8n=io!ZpryHu z4K5VcWVptwfRhO}c)($@cqB|s7$PrfT3Q`nRvB-=+k)9)qn-sm5+=G6$m_{|P-4(s z!>OJrMN~cOIq2SKyeY8)xch_)fJ+-U|NX)N!ci{7pshm3D9HYq6DRBJLlt64Pb_~6 z+&=U5)CsJh7HWX~!1<(X@wb2tRX1Rt3Y&v$;B#otl!U_6%!gf1=-TRrX0*A1&k$FM zFS?&&64){u_=4Q-;023b6bQc6IPfJMHSArEs%==>R>uaus8j2E58MSG5GJ{iCoiQ+c}@NVFT|Wrx2Uttmq=bENv3TnAfY7?Fqjq_0)!9(36MY>dLV@sAe2BL1o*%2?Cy2xJ7MSf z!{bl4J2UUh&h5?Z&h72Bf$bWt|%A6J?h^`USXrXL$7AHD20qI9|H8e`QNuzfYN zLA%9|=0T3R?RGp@$3SO|svJ2ruc5KNrL}GqLI~QUMpm*Nd>G%|+`hUCk6gQIx*9vw z$QimmmDkkSzPbaC*VM?pbX8s+<1g+aoi$yOo>e2OHKj0*wfKhkaV}*)O&OTi+TKIcMER1T`f&*YUF{set2G6V^f{4ey*<1h{?-4 z>+10>^`@5YE;aHX#>kwV$K(ZS57xE2fxQ5WoTeW zU45e(d8j5-_#hy9Cn?KrY~wM%sEc(FcYQLUy;FtnhO zWtuoqh#|`wG;NZh1qGLD;$(~J+0v>hQ>>UrY15RcYUI=CXuNiDZ>z(lH}e1JeY1vv z{SlX?CP`-;dCFhOpPOPY9<%WdrMg?yuA@)O>u!b5>ecAec@aw2Y^`a<2x#;fx*|mm z^wv%_`b=Gu$C}oLy5rR7vvf_N)U-qBY+W&s702NYr$(QnYlg69tq7f~Yl?(NYR=O& zrL1Y`YQPVC?n`Q2SG{KVLVKQ-U^ozeGJ?@eF2nPc=3y0h+Q=hF=aUBw6f^%WRuv1=$e)lR zXHXO0_7nd|BBm^+eZSWCPU_INO$kV1P!3i=aL|PD$A}sZn?|WSA-hZ#jf@!OaEN9m z6r*+`g+l_YCmHe698F>+Oy&e*)P62Qmm2Y#99g$gEDKI}x{8H$)N*0!SS={`8x*dh zF!VEAIzXN=w*Xm{q2+H7`q~x@RY%M*WK#63XVl}GZ0-;v4)t>o1viIxG>eYZBaV;Z zNZo~&nugx$Z>ZeDWr>X%ai=DXnn~u?Wu08UGos4Tz7`M59f@Q(h^J&!t6|mNonm-{ zOLB@uVAR=~wX3BKYotcl`zvb!_C5T`2;#$r4YN}&4jOTYACrS+eZn>7Yh*T_|9RB& zU%F(DQARxE<4~hUVwH{4wbuG|vGJPNF6}hV-Cy$==bmoZZpzVa;+^S3~#=nLF;ihR^7_xCges37coSU2hgN-C!2nP2F8<4dxHS_8Yd{gw3^Z zrJqfYE#_$sgL7q+p_>eA>v7_+rf5W^Id5`}%GDsJY~;n73oz&f-=)cpzM|+%HS$hN zZtYMbF5^|^=oL(w{0B>BR%67S5&DOg-f^57aYh7v&^=;eSAACpy7ue3XS=6TjoQ=D zb(k5klYe2F+b4=8&Wt?L@XA&4u?M9_o@gj-(#DHIR_L`@Bd>Fr*wQOPEip`wxlC-& zIk8BiJ~m9^cw8}u`#n#h?~2Jyv9%+M?$v$}H~ihRU0jW!upx6@+lY0JzL|)dNWtYw zLq;uixt8O#Ku0HkJg$-7cIhkCh!4WH3(}~YTppaxGaNnXa4}2-{GH2$)o~-vbI|>5 zuON!%8u^jol2xoD?$wQ=R^JM^QHA$O!@JwjL&usCEiY6xYLZa6NR{WKz|h1L`5~Sf zb(G7+6Y?!5+$zm=vgMMA%ZMR8u-#zUm_!+|qn}GI7!CG_aM>_*r0=>zUP94+EQtXtneE-?0($`I+k_f{JiC(lSz%-)6lWH6!Opd=vscUq2sQs zM*PD^7V%Nv7P49NJEFg7oU31V@KHZ9AV@``tDWrV#Gr8L4)Pn10q6b_=Utd)B7%4B zNAZ(|di^7ll_RclbhgsP(Om?)1mX+D7#SSb(Wsn>OHf{3x2nsnSUUaseBf+5zjFM~ zmAY4s7Y-eSV~i6WRauRrr=<4Cp~Y_PA{_lgYL6L8IpLjAw+T6;ZGbj#v{U+bRO@$b z+~;U&;8^U!HxCa`^iJDz4q7&`8Xo|j#xN`Jdi~H<_4^=ijkw9Cf^;= z8^Zkud*l_%kL;FL`kJdam8-c%+Z* zN$}r%`HNKS!kPuuH4E@qf_=~_Ua}sJkssYBPkgYCt_VGLv2FeT;e>2H;D@iwF8i}< zux=`Tzv0sF{34+X{8w$r4SrI@6@H@W6aK2L*)QUryYXds;|9GccigU#N?)ScE{H(< z2>BpDi#Q=bHC_nRZA~}0;mLP(AVT5lV3)wkEI!=U7stLeT&5MblL(@Q`i)WxBx)>i zN(&xI*iY;=u|-kCUGl&C?$PzpRzv6v*y@P$EkXRww=-*di$fE)VjP->SE=SO7|Bva z>-7B?l+4F@y@C}gGY!s!Xue3*sGg8?r*GNYdX7!wEmXXhn zmR|nrgbohgSArf6&>~F_P?PvLAP{nLfR;ej)^u~$J0RDn`tN|gU98;g*%A&4e8c*X z2Yi%B`+c+|j`p!{fs(E2V*fnEH_-48!{x5$4;^u@5M!WG^`ug5GSK*uQ~CppI%L9B zv&{dUa@@9WG`H=kX8N!U%TCtTbv7iKv+AkEvN?ezvB{=SrDLD)EV5yHYnfvgt42)G z6PEBKdcDsSe-ztF<|Ld_o6+*J;Le*{$p-h@wJzy>a;;{Z`Uj8E(p*fz79~6I6EM)g{uBX{&w$` zzMdY)^duVRsu_cyQ|bx1h3=SBzQeQV_g`Tt=)j%$S|FhDe4=HQ&eK*;kwf3Bo^da5 zdixFf3=515nWx3ZWb!^IMu>q4rEDfy{#}~!HMW!40yEeJ@Y$t#9MwrsX^e03tM!soa?}*t>bF6>iVDT@SroX=Bo6nws zrxE(=Tj@jp2peR3{oZZx@4qg&Tt4k_v32T_zq);E&Ct$j-9Q2*{-h@I?2vc z>00EQN=j?BMSJ0d>RncQx5&G4WdBEca;k@|Ck6cVwl!6I=-oMc$IaT(EceV6`iTlJ zShuCV+orTsu3I(z9rjyi@5^|TCLnxAE3977O)k*9{@gXj zDDj0pnX-e^%wvdmF+H^;3*N*D4SJ^_tTL;fU%vu|X*5~t!ZV`Et|i(|cq%-gE?YY* zTkFwoCC91 zkISa!;F^ZI?z#@VIiL!*aVP@w`wgl&j7xI)LJ;48JPamb1jU3%aJ8 z8k|OUgnmxZOGH+)t_-jbl1Zh<4M!XHH^{CRqtE)ak?DlOf*p*8Y0!WQD0mmFo`U}v z=9XoRO<2iVu#@4R0e)Qvk(`VCBD=h#o6y2ngbLEWCa@;VzRv=~j+Z!As)C)pCa?nB zutls_vo188_05e~o{GDkc1|Tskt$w;_0rF+{rV#01+Mma%`aVpl~qmM&8lFM0hu_} zq8L*33PB4ZNk|m9S*0)QR<3Gk#hSx{-F?PL735<~kt=xCA|u<-(zRlBTRp`0v1Uw! z8MeBb&0#NejnFN**oZSTpbF+vRCf_p;Oc_d3drbJ3n(IPQ2RV-ZzMi{)a}gXTEA%eqv9e)Q#_$22PYd!6#4{-fdkiuV_^~q9N#TU4_oYGpsKR-O0u4(!KV% z!-(?&s)3suRK*5k#3Vqt)&7fXU*}ILoTf8ez6CXntsULRnV|5I1cmB%i2Nn);ssw0 zu$N^?zdxJGiU+Ml5^zgOUBW$<@ELGa$zCquQ9r?Jh$?AvS)Pt((LufB9GCA!%jfoZ z!*a9B@_K+p8~LP5ealka4y*xo{eUbd`FCtn1ofA6Kjoj zmEPpCZNo_itaJI;;q6_e^mXz{^d2meldj2L;I?3;175dG!wi_=@EZ1@r@FvxD z#{rf;U>RT6c$zN)n0||V=VQ27@PTIRIH;$KdGOyX>*p?O{KdSx%bC+pPB%c~F6I^F zyPVx(jy@;T>N@b!XG2dG-01Qj6XnN!!XH)`fP7&#{gNv?E+~s81SQ?5s?ytFi{wT2lTc2LXxZMpRcVC^&J8Mz_tr|6{i+~) z&)#~JB2VX_N%t9%mNs0(-PKvfR`X@-;|n%2v^oP9X0g7l{Kp0UQxJGX#JM7+Z*Mc- zwC21YBNcM7E9dW(Yb`>>D&uF{Xu`U>{5-3`%T9xypW2v#rG-kw(eM0yTZ4| z3isrm;&9Y^)dE$Vr~8-BiufKTR`|ME$vd_kn)j-AXiPvEK!s!{3p zTn&4CLk*!*;wkW*k|W=>{;K(gTDajACWHR_p{L24SEe6!HLduDns8>Yw6X_Ha&B}` zta#71srwsh;&zM(1@UciTc^_3x|&Y@hMMLrz{WIe7;^}P#Mm6!{g=u=a- zdY!8HwjRJuoDw8(vaLrdJXtXEitiav=9jECQh@4SBQdz%MY7+; zg3GiCw)SQsR#n^}7v)6w*Q>>>0oQdM(&Q%Tr|+nY8G0UD`a1$i(x~D-T7~(ay!ONN zjZRkC;kR@+H*Tr&Pbv8+Zb%jX(gAZy*V?*{>ccR-wLzX|S(Og|CslA?b5-ybPbTM> zQpO~JZL;&Y(gVoJtf(sZ$S_V}F~pZXj(oT0J(i`i?7FutR_2AQ5H240_1DrKr;M2UcOh&H*VozrM+#-mZmi zRi%fyLKQCrti<@nFCwQ;MABzbq?(?XWz`V`N%flCp}2_-1y~`{b&Fhf1j0|B#mEHm!R#pSm}!4w(UXb z>`i~eLKHj~Z$NJ?FaOwD|7N^!&kb*&=-#<#_$O9$y6>#x^D|k`{H+$EVybO@3`BMp zyl-&|1`p7Ec47}Wfj;Pl59}}YFVmQcS-n`&voksP%)%5L+_NFQ^@!<6>_|&0>Uy@LM@N*lQM_w4_SwK4q}7-(O;>RK^PU&# z{WHcNQta=HjVBwK>G~r(jXGTVwKca9{O+afmB#bDpYv{69)jLt(+?LsJ0e1K|A+V%}%3i~89|t^4oS9~Ju!$M0V_ z+Hm&2Y8zC{e;gbHaGV45gO2sM&N2MqQ&$;Ag&%e}!@hzJ4iQ_rGL^?f!?)vkg;qS9#q)hQ^;Hi>nqUalBHIXU z#fW)UTrYu86+bcKXz5CHfn6M7$MD7pT7K9WMqVxqKK1=aNWCG1Jcy(&E-`F?iiRKV zYq&fzXSFqVMbv#V=v4Xa(7ZCuo|3t#S5cASmA!4h;anRrVB>$4dH|tt;E)k>S{HKv zgCV2t#cAXchdHf>=-oAkjNU9&DOAmBXyC)8A!BZosytNb{gu^_T|W7Wf`$D`n!kX< z2|Hw0r$~K`LNP&$2~$k2VoIx$b6vjOEMI?c7Z2jk1^7{A8_9AOLc);o@Y-DeI{7Kw zuK`XYv{Uqy+_}o$Bmb9Jt}|ppn17nyEEE#7!%7Sr0T(z}oFvVf7!lGG2+?F$=tv5g zjp&99rG zc8bL5YS?Gw?b2V|P~$3n?9)vxBxs10C>zVO#m+NshL79!n`Nfo2z)Vb8EV*4O0;zC zzp8y%-6}P1cb{0Lt%eqTf6;c8olO~b>2Z7b*llm-q|q8Q>_M`wY30&6HEvHI_cUEu z9b?m6Y{^;Bc=yEPM98=ryQVZ}hHBjB6q?Z)k zw~~E@!y&4_jOwqVdS2$XpE<*xr)s^wb3ZQ6n`>81PL)b{USH~RmQ`7bF@leb`z`e| zTO<9v!}cI=ck}ADl?(7#7xQ7i#0-}ZQZcNPVs)#qQDJK%cDn3W8xV5|VX@mN*4fBy z?z&r$D^mUHA!u7OaiWg|(L)A!x4@x~48?|o+|+Ym%kY$rIo@%U ze8)`X_1k5RiC_IDvL7HM`FCs^Ma zfDSHoh0R=XprNTo4;{-cBXp9*t^w@mk_&OLn)xx|60Ca-p!t`;!cO!@I5=RdcsS8A z*Z{D%A~uZ3fW@n=N-jLCGDRP(N*#?8nc-os99BMn@}COPrSldHWi_WnCFi5kT@yWY7fD&Lw|sq`+P22iU~zrk;Yhq#;-F30qic$6e%S`M z*ZfUR5jm`ru6GHKTY@-=J=OSeqs#KVpGB2C=Mvtwgna?6s{cvCui4;%h`OTAI(OOt zkhuJ9@af`1T<+b$I#5W;elGdbiJZK35dwTa4oqSmA*@hF)uZ zkv@hXT)&t9o$Q9#MSB4=u5l6M>3xKS*8t|5oe+AvaNPBQJ$3luEYNR_Vosp6TmCI znRr&#w0LFgG3sZp0F(p`7;|fIlCoOmv^?eb)&cVj8W-s z7h;bDhPW6$TU7cUVx-Vp@@Ho^V~VUM3|aBHi!e8V6&Av8M0xdgFoJ6r^N-1Hgl}DA z@R}y1DnFB04>C^aCBMC%;mVG7zD;2|6E#b03+-#9> zt>(lGw_V?js+h;c+Vm5x;`|Ga|Lw9^p%WGZhE_;W%xqfbNTh>OKrFGfXHQ6>t znyboc2U=~%Z*6UO6*ZzzoUF=kq*gA;$bTiff9-M&jJa%BovNf~{}UwjY&6_u|K zan!XOUm}xn0!NrOlkp}9m^oeI)*+K2b;a+2qDp>7g3V+I!4BWQA|**CLuX||ISieD z`Hb3&X`CuMWP6L3C5I8glgYK@d5SckWP8efOuz)$3xgNRTWABdD)smSQjY>B&K@RlQz1=!wCZw)-395XV390ll z6JJ47RjM9586M`Q{tGpgj}LX!lQ{4)6Rc)t;*V6&OJ+hhwdb4!l{iJjhqdn$%;qGX zWu3ORq>#r#Ku$svq@PJ!N=A`ta}q+e*WGGTdd^9Nj0lEp3oc?eB-AJD3LEeUQOLMYau_mLEnhX^*`%|LukQ~lWGP7!M2G7v$8NbbQi zyjZTYbQOW(at}cuH)C+OWDEpGrB8H)!&!$Oq`wsDuh|?`dM~Bp@(n>@lPB;iF8$aQ z4QCo+W&LW?6S4b9Y>pu)>LmugKsPepSLqH{I-FhTN&LGauG^fxmEv)Eg`l)e2Lx2V z?aGET3h}}L#iL4~I5w9M5)M4ZGFCTHI5vwA6prQ(G(h2M|>PCU|#^tfSA9+v|Min}v+p8+bp$`uaJ{(F%2=~wBSDIGWO z4+`7qdO-8vUD@!AKVI0cxV)kaisR<`LD`sDzV3YlQ{_!WiJRpIQG)Y(eWNIQk+L!K z`=DrF=hr$)_-+ivJk~e1^7(0_GCZ^2GM(<6Ub{vVxGMud3;b|U8Gx(sqZ|<&p&b*H)7&CVd z%6XIP;KLToTD2A4DVp8IpcXf4?+Nl7&(~wSNbGz)qORGC?P5^;0>;NxsehsE z8GXp#T&dW0oa`QyD{D`3Q(PBQl`6w(p$r#LRi$>p;TWz=(hF)9j~_XwbvAONSoP7R z#*eylrHrnzII6lCi+9G4J`Cv|Sz=|@9?j>MQ2EjA@ngo%C2u7cQt8!7sN7}8#jME7@xNSgwi5*?E4yIR=6Yy1-iTpwuq}>;8uG4Wj+(zO5wQ9aD@k2xF2pm^lLI8b)% z$>0^!D{9zu)nX*-3tiUu+r0maT4C)u0!EEs*tvdY$5UuKm)=Crygy@j=bJgizNa z`8dAHm76$C*3D?2thGm&d|-zhYX_?}sd zUe6)tM8EaLRcQMA(YWr*ami;!;pZ@}NPHYkSe&~nmt76z4|638js(>q1rOS#_s9xH zRnlSWbH`f(*Egz#_mIF#N#(N3VpW{ySxkEB@cx^BcXw=XHZX@KSd@Y}Kq-5hH5>@% z(x+TU>Y-rt+oBk_u;7YaNw2IMJ_b#Yo+O+qcXn9&4E7@-@`(Z87}O2oLQ6HQnc`R- z+PLnJ;=MCC}6j0P`h#HET=smq}%!f=xWk7z0X@4C)GB@^pogy*!KXy+HUg zmnzD>;{s(#o%(_1u2B3snq!b;N6@loiIgB`x}rLiF4acqcFX-;r%TJJAwjxyMRhP! zig#hG7u`)uRaqm^lH^HYUL-{-4pTGlB1VD~>56K9b`&GckVWFJM43@I-LBN19|YlQ zS2`;KgQ&s?;zNd6+AQm8YV-Y#_QKGNr7ROzEMhbTg&oK%ZRU z)*(|Wb;W0*%9kmXO0Uz80ktZ1K7KPi#P|bhDqpH_)QLFoGNr6$rt~u~^_D4Jfg~yR zfsHQPB065b1u)DU#6LDg`UVTy%#!gg0Vz^VkiI32D49d5O_2)KURW2B(sPQ`S{2HT z>Mrc5=`}ZMF~Uhv>9`uh>$q^_>o6&Ex%ia7l`l_q)Tlu^CCUm(iI(gNyKPF89M%zg zx&)*|H9;J~PH22}gv)}IsK=s8+Fb%tqMGm*K&$F=NN`i4La`2fl%$xHsA;v%g=i=HQNF2PWiYLsF8PbpDm2VT3)4(b)~|&&#>5IBK9%u zR;4#kEH3G3q)fKcud4J#S05~4$~Nz84s!09Hx%Hcnm!)Ml3E}ZpFg6$ADbK;`G&&i%U8hIXBzrQ>oI=x>Dh6V_3|mQKj=H zL0Mdy(MZ|+VnA1wD-_NzhNS$e%1@wFTw>7(1u}}>wLuJ3eg}o)@`*+`m`IfVrpk&Y zLntPZXk?OR5LaO4!<9iRlrPX0^H|>#%D-dvgtLd=NRb)J>1#%`xVKVO_7|#(Nf{bV z33G+IMUm#HvN=;Md@xh^P2jm{O~hfWQ03pInz#g^(PJ}%@=k(w1n=akd;XRU6+tn93-LdIEtFMoF zKd%=DwaN8`0pPnB09K{mLMt=+kiWT7QOWNX>~g7|TNY1)AMD(6JqQ>ePjc%px0Jf# zdqGhp2a#asmO`*2xF3*`WNztx+rT%+#Fr!V$6$*dp#jA=P+8f>E@YNjW*p>PV)9$q zj=_}gA(YLXj+zAXO%F0O@01Te7@tUQ((}$A5jVlS)58tUKVdCHr1rJ@SqWA4PvRz- zfqKBvp^P|H&74DTB$$bMQ2rSyEJSJqP7PQoUQIMB^-#UpX&8<(Q@*5^oBAPa&G4{F zDypO+H}yHXb5-gA5_y;_hn3|s9Ch?yJwIi&%uhdLYwf=Kkzo(vCjQ+Gp6f7OHufL7H9lHkr?g<{?MU6NwvuMrREnJo6U+k@8n z;mcnnM%+v`0^*y~a#slpF}JlCvm^>bn%{09yj}qNPF|(m(jPp=DPsld2lZXM+$;& zfBH%y#Lb8!0CsL1FyKX3JUln%uEbkA7!Y}&;?d%>F6`E&##y8g#_Qp@xW}`7o5`nB0}73I|3o|ZVsgU;X$RR?QH?V^X_;AMogzj>^C#;?+_t&1|C6( zpNspzN*^Uy%v?MIrDx@l_LTOYWdOpn@*WT(?Md%Pgt+;61i_uD`^-@3GhO-cOuc6S zpA{=Ai8dk^UEzmF9U&)$2K_p2{Igz|Co_=tF5M(@8;iKoiHOQ5(peFP{t zyO;irT`OioJZ5$ukxn|#hlSWhR^9=^UD9`hDdw^MSy0&J3V#^nom)-b2`!mjQrv+pEmT*jam)P%VMd-6=5 zakYm!O>F)ks=bey1gl*4*Pw2>vM~m~6$9$3)HIx!j6URVu2gJ0zKnZpRp!od)OMHY zq(U1qxLk1tHjB^=G6cN-Fr*4fqoaIF+;uAB5v? zaVZs+&EMa`W=kye04o>vARq1s!M&BZNsl)Zt8e!$B~=b5yu%;R7o{9gc9OB^uwyu6cTxuD~FYrqr7N{PCKw#(hkk2bkh#x zK+iwbtwY*D>WZ&Ll`riem0sFmFHoyeKgMr{hq4o_+C>4#XvND4yl>Z38eivmv1pwXGz#sB=RoOL87wmaw)1S=#3v4ozn zDF|{{H=W`Vkb=+zaT7bS@#GaQ3sMjsiz>O(B_IW%3Ht+DRsW6zHw7US>)ss>0x2#9 z5$6S+hCnj!Fk0+aQQkGxfX zNIIfdkkbX^D7I0RPB<8UVp9@v7$z;@H>0%6MTn#&dV%m8k-m=*v8jnT1TQ`D6#AX( zj;~yhNP41oltTnX`y)MT9!!Z%QN)4RG)2IW(_M&2nxZ$1fEm9bMtrIw79)_ZFijbB z2r%N)6>%8R8<)l@uOm)u$|4TNpSFnY`{g&ec;U1~uXy%Mo7BZWi4vc>h=YlyFN~L_ z%m+?<`XUY|l)}&;Gmj@oTnZx&B9O-LB7;i*f+(M0q7dHhB(MO~-l-&&!J(UtR1Bml zoqMPSiKH^(j1d&ZB&SH)V$vB$5G6jH5r-0=((nP6UPZvTltvt!PHRNkR{FXHiKI1p zMv1g7J@PP^5}VqHLvhm^K66xhg^LkMZ}bY{vqq(FBS>tDBM!r+IRbWk=t4x&9KB)q z%_y&005f7!9dQuBbcgQ>C#EVtm0+>yjySMj%0sRNRrUoT;!+-Q2#M1k_)O1ao%Vpu zz8hFEkM&)-eBDB$Ig<9+8mc*s_4!Nmx`Q88_9m6br9R?xCry8tR!17F%9b8()rHa@ zTS47|=`k*5dsX=jR2!QDiPLM-Ao74!hf0pku>A>PV$&dTFuqiX?ql<+j(~hzDkM%k zHXVX9iKKuRzI7Lx{VM{;rbBv1PMQ)iC)D&M*Md-Iicg8eTF}?DNZ>jO>X!(BDFR<< zs!AP<6P3}2{LPh$%FmB>)ZaM(#RC45I0Uu%kkVsNP$l1Y>yQtTy5bR_sFL+0*nEf( z>=-|F6ex-EA$CjMP%eZvIYqnCfZ~BvR(6yNnJpI*11WisT%sAwp@Mk_F_Yv$T*y!k zM4PF7B5}jyKxloE9Egh>oBzA`f%ru<|^V_aCZr z9;}v}$6{2vIS+E6cdvHqkn@nb;)_t_%Xvtpm-CnmD&Bv=Z-$4tsY{@yvj1X7Ey018 z^I$b|9@{R0p5AgE))jUX8O?W4k5fbyFnAR4Y`$X<>$Jfo`?>_=J2XN1q%@~wDXBK! zAyj*@-a$$)`HqNvp)qwp4a)|=t49$^CR&&e=9Ft>8P*8=a&v; zh2%M^=@FafAcu8Nvr9mpLleY3?6k&%r@Ac2b9gM+3Ew3k&!Gu?X;D?*O@f=}5Q=r{ z=Oo4DIl>-ra~%4uNgsT9^%7vj<~YJ2k^F{dez9DZ>C=f7o8Jgyxw(z6FXLohknr@+ zm5<~$dIXsNeFEIdv!F^-OYtW*uMw6vISs%1(%G(bB&X4XxLXUOGs4ndF5~(g z{mpj)BDsv75q1>>-TriL4NQp5V}t>04kKVdwJRRUVe}*)P=7k*^3j`)#wg#R78tR4i!ekaXA$ntho7YXO4kq}Hb)VLkjw&yQ#Ob(0IKwLE4^a$XyLZv6x!+_X4L|ESDAOiZ2b;Tn&h@RyA>dSvl`PlqJSUe{8 zp!+8ARQcxwip@QQfr5Dlea|UtZ-97Q-XSdg&2kRD8%!~e^_{Z(Evq$>bJ$X~ZoWbL zNOZb`5LLFI5zURuH-z=}HP;Yss49ERRTauLY@sUV8N%Acx2imUIa(K+X9(*Ie-2p9go@jkI?XKLzJ* zr^2uA(X=_)b|+>=Q1X)1)$?(3_km^bi8?Q?sJ_Cu#^Fs{#U zG8cT)#t*(CxR-CF@e}16**<%+w%cp=8myN>tMNs@?nx7tw|B0s>uhk(UQKshljn)d zX>fw~Q~Yy`C-(XI3hfT<2>HxkU3Y!+|JEbkV)UfDfk*o&GNcc zU5z#T-d&HbP;|u+*o~vBv9tSs-1Hl=TnXmx_)S{t4i&wV%p+NYf(dR_>N*7G3^zx@ z8WjBEg$PvSrtSq#Zi-(h%S~|~kt4YY61PL@PK^%i&Vmh@+OX*eHcm>7;hSGMJ1^FI zEG=tag}Pn1ek*6^=6**FTZLXl1ji{Nm{a_{2chKPX|_Ivj~i-&-o>Sh1lh$U#cvNz zhAbvlv75I%3Y)F4Y~C{LdJ1FjC~X-x)0s81*s*Kn@@r|3%9fNzvOLw5cBE*Q=I zUWD7!fLp&tA?B%>iso~-oz&ijvxmKQH2=bb$luu7(yda5+m^5x+=k|``OSynC6%0k z{ld*D{voU^zLD<29xviUVKGhia$Bs;m94aLWrvqs*t;4;|QHGp3x52BpG818=ElJ zuvB3Z#-|ZBQNq~bMyKxLP&M-vLM6!;TcjS+#XcLwqsh|67BrkK_Rtt;_^HC&)MT_j z!^0}6sFI4@)Wzs{RjK(T@-SBpD>tA#xCs3iTgI?j^2Dd1(#;c-10DJrw+?w?sVn|D zs(g83sr0U;MW9xt9>Q;ihq8Q~-@bbj0W}bM;vCz|7p4j-H=QJ_ZI7QR| zdk-d@O%qRJowm1RrAt7XSQDfpN^43^C)K8jg=#O)&7|~_CJvhy$`b32@9FD3OB@F4 zAxW&^ybcd9PefBQPm06&TY2gKIqGNP@JolXLXyNQ=npqZ3=Zp@^IZay#6l3~u&WyX z-RQC~N$j$yl3%z4CW(b`6@FFqizIkSVp6PAhjpP4mn053z{?Sfv=6hGhzFGafa39~;jnlxGpud@3&rCz!y)nL-9PV!5A`x4BT^yl_uYI19e(IK7?#@oC`@LQGazd*nkx#Ak&=5aFb-$j_X#7V>dP z;gEDNC+vDcr8@}_n-dNpNJ^NarJxV)a^)i_;Wz+#-gIS?5&oJ0@fqO|Ko1FFuQ8>2 ztpiqELO6t^^TCnEl%8VcBl+N1fJkG~zaT(tIyeO2W`li3sPxyacqAL#lf2IcmEQ9> zsEacSU?+P-Fi!_8D> zPr8~yS>P?x#3XQ7nK)LJZ+jxz7MlbPsSM_T#ZNclSCtaPYKq3C zfJ2hKWq`#J?_|v`V?}HRxJOW(6UzQ+tH{DKeU}P#m-vNcVdYz#`;~T!YPp^<(w>Q7 zE%HAgWb`3_k^e!(j2pgOZA_db9DJOO7%ZDhm&cJzN`O6tiK|M)c+`?RLSb7 z>aX0&MYgi|ry!~H(v!e&G&Y;=-^e`I+!=0idE)d)a(T}Dx$|w?-7oy{#X+-=Np(Xb zvN1Zs-6NXQ4-)^@0l;tB3iut|9$M!O4F0f_f&Xpdw-SHL%mZtI*L8dJ^Q+{(sWx)mDJ+7jQGJ)Fy^;)<=H0>i8>MiGW5r$}Gr2z>Nk zRcbvdGrazDQ=53GYxVE%Sg{E2Aa9#n&R3DQ%^k}>177`(qu#*5yut~2ZTN_QDxAnF z1k1d-?(R-iIO#D2!knFl=dHmP3h>PURXADKjL54;O1rzUK^0EfEIgUK*7k;$;66ufBbC8_HF> z0SDpD8Z;FhO>MJ)(OwPU^M!-)b%t#UXKRi7YJ8Q~0_bWjmn!%Y{jzXBjoM$$*zs&E z2E;Rb{~bpj+VPHa1R%XT4q0)>>2ND~$C1k7VIZmWGo&QH<9LsndcNc6qH2wIsjeWK*N>IFZKm<&Kj@g}vi2 zJYi1?i6XecP-RtWXB0EM{&Q2~c&KanJ7fNL9r@<5KPW2wS&W?Om4tDJ;bcWnJl(Bi zP?XBzBS2E=w@67I6emvbJ{;mbmFFS@^IE?iiR=YRl zw^2pn(3n62qvI-?ubqXj+n;MSB#DlRG_8KfLQeUEGb}cq=GKAR}fH+C5RjI|O%rH9SrkZ%D zYxz6lj~6+zhqOO%^0O6^zxXl1+`vgz1kMNDN(N4;EPe?jl^*;(FeDG0E4*lFc3jqx zQtyQRhGiT*xHRE*>(@)EzH`sma4z46uo3zVmM`{$mN9IG)8In*iqX zgF*f+k&_3oIA|TQ^r@2$W}rv0eIIAjG|gB?#?uF~Hm)L{H~-BEyqYq_1+sK&q@teTvEqum9YXgUd9dYxz6l zgsUC(*d@U{A3xV8L9vS0v>O!3ilBIuTgjj(mBpumgxy|9NgfpE#>94coTNWDbDpS6 z=Uf5Mmgp8RcCm|@B)av08E5Q$1Wq2(;*d=o^YsFA>2H4(uoK6zIA{~Re6BFi?SxJq zykfC+#M0+a`kBFgg4l^8RvfemQ&F==u>&R#Q?b}OHbuBt0Xsp+#fq_X&WkW~7> zYrxQlfRrW1N^sJ9Xx}EP(?6wxJ_M&M3M5eJkJlIl1=m7B@<5dhpF!(Bny%fX(j6{- zqM(%>zeQcc(_v174q(qvN%8=eMTrEnKqIF9z~UzgX4&!M8gUJk^dYci(PDy}uQ!=! zk@_L@BoA^~)R=(hbC*%GifZ~0@UrRA!B3xi>AObHv(%G3_+?RJ0%5c{d$3dYArNNM zql03kIeiL>S#;O{$x!7K>FXWwkUFbUH={DcNRXSli-)?FzcX&Q(UH|){%I_i>`Q?B zfM9NbBr5{sHrLxq21uza{wYW*-9k$80GVJZkX|c!k0?$*PWa^Ev3Gb0j{3C+13&6V zfKMD8v!F9HK1{QC$2UR2wioNSFA<@@^ObprK253nf5_?x-0;11RM#%|Ok~|=0(W1klKI76`jh5G_ zC2=_HU5N>X(WdOjZk#+AX3?TUVWcU235C6Duz`>v3G06(bRh0gBi8?*nBi5A^*=n+ zwfvp&&QBfL_0b;)xskU7!p{lg212qT5N>~yt(1HoD~mtCuS%~ar4NBHu+gBG(+e+* z)H|7eA==X~QAZ!5VRju767}BbMn~1n(2+bOCQu={y<34=q@9?)(N&QsE+$gZqJGWu zrB#?klKHowCV6nou1Dwi{7pI5Rgow{CQ=dCl$WWe4`DL9A`>fp{mTTH{eA*f$zx@9 zO*Y@>`ORorPfdLYm;f_D8m`@e-d#JGpQE&KNK^J6UhIe$r)YC-x+(XcNBN3_Xkma;Y8>E=pQ$Tl9l;C zw~|3rDvM`T{h@^)*!`52lH9nS7-52kF;F*NQu!D{(YU zqRNERXtOp`Rq}9}NSDc1hMU!wc$!3y4X6xlHZCB3^75)m?T^X~BSvoOFdph!{?1r@ zkE6I%raz!^t7HkN-y@hCP|1pbdW&1hfGU;6%Ro};ZSDj^UjnMTM^(?kRBuezDyq{f zsh}^xw08x1Jc`CTMMlAsRM3Y&ngyRhbRA9CZc^z9cUk;oK{P9Vi{c(s_B7}KdI6R6 zA%OO-M1p6a5udpD$%1EA{J2Ie*?>m$C2;nx#RN@XZ!*#4QR?YK(Cl4}379^288y4! z4K;lUm|67bV5!f&^j)LpV(RHbucONWT>*& zJK`aAR;8LznPJ$=O?B~5*YbD9bsHTu>*8R5dJLfAj)uNqXA+j)mEi$LuH0>A~$s(4|OenXDr?1sQbBN&cHlp zoFjXLdhdr|7ffHFN)0SByIa=iEjtfdHlZ4OQBK4Dnhou(HFfp%ja^-V9Vx4)$ljiq zpnE{_P346XxRvF!ngvs9l)MO1%wO+EsTl(vaMask+F8c5nq@ORn22$gYvZuPrdU_Q zmn*qN=9~m(PNSJM%jSF|L%HAKh!Xm6AE)#JSS^06X><2Xg{gLL)v@qmwJ~(EF;wrv zDrVBuYHdv0ocZ3{NBj)6-(~VzVKINbA5~fiL#*!AZCx!*ZH*1XTiUvzKTzz84J+`H zzSTX28?Y)_oLsrgEq_FvBMV}*NS~2$3k(i+!xK>W6!Cs1=HDQl&nB4=CAjo z(9bVL`!jm4L>^Y9?p(>=&A7uK^FDpk-l4a;9p2WsRyj*+j%i!FV*VP1F_T*Hvs7Lu z{yB#)T89@Mb5`dquBqt&6Nx#i3)Pabzwje8G_GpwZdA^)nqwMP&0n*iMp1gLM$j^O zi>&O@BO%+hwytCHq?&1!b5%~7HeGT-D(`9ha}Hm;##H63K2a?_#bs7G9!4V^0INb*d( zNB~U@Imn7hE8YjL9fRU6xO&&2@!t^#)P0>&iq#JMh*|9jN7c?l@p*8a29EE=aMiYh zA*CF30f<+{FAMR0CfBKDZ`;tDy^fnYJ}`soWVSz_^^%-AZL1M8B=w0KvC`R|&3PMe!Cx zQ02}h7mTgn8ypW3uU_h_Up|ju9Sy5sbMAf|QfcTSoQuY%AT$dvBIYdTiDC(j;G5P> z|HSeA`1cr~o)e|bzeJIzv3B4ij^ZoQtbbc*(m)XxhKXR{+uQGe_%Dxv)w(0_4avs2 zDBd#KDrX7G2aSdDRXCo8f0X@PYw^{#^~(>$Hv`D2j_~a4;z-<#+K3AXEH$h~1<` z5455e;NTVD>vPHy6qe6`!u2?&PX1+dDI}*1NzTQHPqdYEFYc4J!uWdr{vVM*t$8{bTtH~v|+5t@* z0-{eXdkQ;(3}{*fA_A|<9Gt?rp_^jrXC*y^Qo(X31Gm zQ`4gQFUolU1(mts+W_P)Ax&?f{C)f**hT?tz79ot^r!N-P}L6jHG)JJdIjijdP-Rh zrMLpPS7PmMC~~9Bx4<#vPB;3yT($GSPz{|VmU;}VHnxLUC7YAfo{P$5*rthm^MrS0 z3HJEt|7i{>ux{ns-2LU#oC~A~8y4U|eroT*5%-;>+_jz_V@Muu+B?F{wXc9}91h5` z!DC~!F^4$m$8pXMzzq`|fAP3jO)hiZWU+*M-ZCJ{c^iZKXogQiY7aye*Gv%NT@QxU zS{a`+)}D&uUKmG{W4pWPLTPnDYaS`K)hOzF8(RI@r%E+m1>!OLfkAF&Vw!5Y7nNt= zA91!9tmX?eh-%!7gENBy{wVMf$P^y}v0^RyuoWHf8%Hffi?lA5(8SA8(KH6flq`Y7 zZd&TUR%(CHP6d-s%CE2F2SkAT=BEqXSJfNj25{vz!B1qaP@0+yMuLyF2=3tCgb6OJO-Vt}mCK)*$iK%3<+ z!p?ZZL;3~rJhk(|^BVw?ez)*Q*kLt#0ZwPxTwJ{?P+W1OHHjs-m|q`kIv2->vb(u@$tFg6$|~9WEqV zbQumQ{uRXfZIC;_5)^qVn&dCe={-2$7ZrV$nR7~t%J92`O@GEA!BPMz(?CB&kw8C@ zzc{D;eye#%uZ-uZ&4A|t0Fu5$c;uY2TAx#X9kKC16uH-rHc1AIHX@UxGTcC;sSAg@ z;NMcNNBiGYM*t$3Pxupqt z5Ayik;c%7g3sSodZ1b*AiYzAyn+^7)p!GJ`|DP0boe)@lYB%6$(v?b4?lzz7#vD>y z*^N2(M`T;aJ>{q$WE@raDra{)UhFoA1cv4MnW*0Z^$q+)j4FIB!&A7rqrM6Cf51QN zDplVt+g|;Z-~Y^6y{`UtmvkJqv3ir+y>q6B|1xc@aB>H*`MK1e!Pu9@VCgS%!9u0E zp)j%G4Fo77CzB6}YA-{HyP;6}4G)3UG+Jf24@2#LQ2ZV4CFI!i9`9bVT^=dG7N-_$ zm-n?42e#GJaNblfFz+keQ~I&>??H4DMB81`doOT&g7Ygk9)0&2`Lv_BV~g(EEV+Y? zu_&kv_iD*-pM$0aD5vnR3ZMszP0ib(2wlxZ@)v#PJ2>Ee81q0sO?bpVrgd)rCY#s4 zZ$YUr&ruZki6_Kr-M^~_!zE9nc=`ZGk>htUT(w_=;oJg8Jq2RsUbj0Km}vjr=^5O3 zcR~}vJ5Kl)u}VTYyJ%Hv6pESqcyXPLqm`vfk?-I45qsGncxSuEb)PC+_Gv$_G*Cu> z+dWR9oYg}XRsWoRFRGsc;SV6(u>ymk?VjY0ZPK|i!@*elG=7E-Q|dEtEVy4zxu}@z z7#%A`hb<0V$zkSplO4)IixQNo6zA);mA}We0j!0<8MZN@xfJr7dkln!LO5dXb2RrP za35HPuVH}WI8m`Ok-3x;bBWS;JxWhFsFA^sjHms#p$9?!4*nev1t*J==JQ1!x6D^? za3e<5T9hTnCz^Qxq^7S>ON>(>d$E>(97SGdO(lQOv`bKbQ;>G-9-y7Hty1~(H9E@y z^rwiv7_~&X8PXdy!YCAp-na$_>w^s|W*tVk6#W4XDZU9}4{OooDDqnBkiWPQ{sIT* z2ODT^grum$^ua9jP40!kYJGj}-5;l7Hxw@! z3{g21ECpKp<`8I`huZD%F9#?C1gW`*MYgyV2Yc^eJjm{(<&Q#< z@=ZT6v{KZM57Lf(614f>^3Dg#0rX~~zl&O;On~%kjc^Z&VqO2|Fs%-@u9$Ty^Bx;E z9)}d)7h-d?=%-q=S%Jiu(0B+AMh6>c&Ic)Ywo4n<;gDbl0;E9$%|MaoW48Ro`M3fH zXMvgYvxP^3B&+rLczh_%$Ac(-IuId3&Ie15sLNmYOB`byG#0^0awYGgd@cT+1FVO& z&YMxB&O7CAp*nWkKRW7LgFFukp6_~T+64>*dISJ})F7W}5Y;#bw9lYUo5GSYrFI^U zRpyNfYsy-biL@CAA83@xDAJTY->{s`jv~+)0PLYbey>4P;|S2MhdSLbmTbdD;~0t2 z-K{C}Q6|z%ARM7l3RwkHhRR{uLd6CaJnl6x;*gM!L%`<@K9>uCA`%7i3TqlP;M zMZz`6Uv!g)aFE)~QOiL;TX>|Kuv&MMm!~2Qe}W=+Y&i!U4|!ZB&Eej0$>!a0$NmXp z#R+(S3IanPbR&X+j@~Ngg8x{ULf)AXel&d*7`SzaZaPbD(~m_#Ww>KShA-teU5PUB zh%;BPnh!^jO|Ox^X!=GRyts#>4g$U1)5mJv^s$&X)_#B@_jKq0$BiDB$=$e3C!5#w zknhij#wIXug8!yFqv;H!QH-Kv?IL?XTs{IlS zd@Gv7i#!Ha0|vuPzKL8VZynd}{sMAx7=@GXQQ@^Ccv8S^NAP<|5hM5<9LP^?BaSwV za}?!;JIp9%C*ZO56a3*YX`j;y{mq z)!LB5anq`O5=Cy6Mvfwn%bhe-$xdUn{a!-m@M@*Va-gtTOG)urnkPkAN?`e^9fvAz zlt{T6Ple0~Ac@-_82DPHK9MZBCvqVQNK4)bEWW(d^nWN5uNFA%g4JA!B2VN#@)sxa zS{yWY;o=4TVox8d^@-%J^tI2T$k*O30ml;_m&usAmpIwHOFZvoTs~_tu!O+yM_i{H z=;$Rr1N=3}C6ae9kDsG|o`c0LZ4Hg<)HW0KQz%5cV<5m6tF$Xva$Qk_0;1hd;R?Qj z&~z5c#NQjZhX{7_Y!vB=gXJ$=aSIL_4?=GRz01?jYVC?yN5U1aqR6*ey20@ikIN(> zU00CJbH( z>xOe_d6g`Ku00o(&t9Vx`92U{dmWMj!)!pkK#I5y7vMmCYVX0(>2NUR_I}hoW3Gc6 zH-q8bA$Iu0k{v$1gkzPtWe%Vu@tOKF%takx)(TYfLnzWQPsm>kpGJZwcL#6yBzXSe z(=0F$XdM8~)gS{=l#^74gJB1vAVXA^?C@zhj#Xxtxz?2Lp-iOnfN-NmnTsM#Ib8nY zs=6HqPY<;XW63sb1CH_T_c1_|?B6RW6Ol--XtXO(B-)SUFB z;Sn5|UIoC18su#aq8fJxZQDh*VJz8(?S*4J?p{W1?6mb<0Sbl0Z;i$R>cQeRMdCa{E zOdIo5=No@@)axVRsJ)ybr1-YE+U2q7zg3-$T?_dsU9gxZE~~i1{+xYTqhtBNReE21 z%Q2)r1F#%`wVU-4g|nQ^I7R(dUvM(3RN+1jSLO6uecs9KtLnPCi8fo%`mMhCY;m~iq~Gd0PHtb0?dI1QkqswzJ^vSkC20NpQfS4i zKKncT3{1b(_nln70@cr>x|<6-3J-9&_@dwHO((Z^slqvq&ROo={Uvv-KTyofS-r1P z^&7vB^&?jS4IaQ+GT9gZG}Gb(+B-VyRpG_XYsf4E>m=^9f1M#7Ld*sj!Q>kV2%{YR+%3u-mmod&I0qupiDR%x^i z2Cai>Tb2I_Oysu!Rxg0js&m5MFq&Y;8RD?hoEz;p^#f6NHv0h1#!zDda=^8RLiEU5 zEO0=FJT0bE)^>v7bo5#hzZ=JJ3mEP=%26a<=P?A+$4gB5*ev84sA}J!7{bx@5P8xQ zlemQINV3lP>x>vmZ7P4APU8<$jk$kES|b?C{9&*hWa9r8xZnD<1h5ZK1gvVD1=_9% zbvkg#g94p`*hGp6#w&10kbw{$s{txdWXPH-e-Q!C#Q~SJYao`~2zUVsD#OL>87}^8 zx*ugi5^9Eq>qe1qC&^z#z!!1wI8wp8gWf1S5&_Mi84O>5;b3HxmxFjw97E|FSW^Ra zBwpz;uv*{Exqi1wmYdcdjmlsBKq>P5R(Ne3BL#-pIJQ)Zh-2kAke}MqaC8lZ_mnGr z+>KH0@V<5<7~ai6Fb8qG#}Hguu*9q^@Os2&5PLHhLl%e}?TN9P_M0AI#6mqHGq*p+ zo275!o(=?kN<`4#Eh<6&5@^Q&{2EcvJOEX|R<-Ro`0@70IiY^Nr(9BoR{4M>$2(*% z^lZKrVylN@ISxc#^2Au}v)PD+ZGIMljn9A;SER971pPL@3-WsWdl}&A-$+;9h@#lM z^II5_jd9d))K3Y($?mgzlDoFxF2IKEL5qT1KufVg@@(1VGFN3R z(>S}B8{l!AlXZ3Mkpct^ktlIJ7OX0g1&>o1pJ47Dv#AI6HomC?iKC2ZFUI<}* zYDC6w?*1SX|3TvZRyyHO6y>Zo;b7mnR#c|e=B$!p=3*D%kRUk_F4X{svWT;~NdDri zZo>x;? zr9Qz80YOtLTts$#R`;3%jfbIlXRxh)H?@I08UF};yMQB@WUfuvQiIcMENi z9())iAteKu zUx=JsP{CCvm*$X--jG=y-aEibg4%_s`@=}39)j4LB8n@gP7QpD1btO4b4wWdl%cxz zc>HkN^tT}Jfv3-1dRZlVlGok|wugVH6j??*MSt3X6)6C>1FL(b2y_C=Pwl%n;-2r6 zTO_j5q~K$ZOLNHPHmP>-2k_rGJb8t{a!<%jR@d$W2JWm+;E4s)~N+8=`Lmg|%v%O+v7ttG|R+8Zo7fiwK6eGxz0@R@R- zL{yl$`lUH!^IEGuL^rF#LqrIur|DjCk(Ya(00wToO=79XAWv_6ttFe++9OcfzaIvy z5E$hNv09Ium!@FwMJQf~VJ$h9dR)F?ZJQdfz$`Udbl&-91oAM%F2bOcBH#AJe8XBy zZMuz^s{Ih`{2Ufpul3mNihg^#$mTU*$B*#*`2dVwA#k%N#A@Au83=T>3s9Vodk{HZ z^SFE~M`IiCZHTquHbRlqGp^5l_n<%neg^i!QFv(stog#eh`Z6i`R1=LYP<>F{-g2z zI`Hi(ye4WG2@^GRsc_9eu#Ck&EQ0;mQGbOXh4%9aZU_jPk{9u7_l8{F(MUQ&X1>Tt z|6#Ru)NY8GwI`x@6sEM~ILqVmO=)8t^;3u~UF0Z=-0F$>rnCV^y$kkcETbXo--TUP zn+zQ5$et1i6W_oWE%?{HIR~blVoY1peI7k>swu98r4v6v=iHZWc*j3@PPC>O09!Nw>nuS1zaX~*smu4upCi%Bld0 zDH)Vi24&6O5U9gHRoe=f+jmo{0j1M@F#ip}n393{uQf)GFksAcK)JjL_h2BrAt-V+ z1y^5wo?~L0^zQu6bF_+q(uLgOkoxlg@HhPHX3O)x$kE!EqgwE9N8ODf3{~vE*$qHe z4Q}4+)Zo*}g@{=HUvTXOt_D=|O{>9Y^QMnCt-30~vGcP?tUiYYV2@*^+2HfEl69(n zXViU)e~@ZXgD>acqu=UVao$wss+9-{n;`oP@+SuX`Es#AU#vy=lqS(lH?c+2O>A*s z{XEEAhJSK!F%GbVu}ux!$z&nXOjSGdGrW#BPATF)fPWY}nCm&9W3o}{UeB63u>M-e zY{b9l^?W3d3m(D48&K1K@{nsCe!>Y}v)8jOy4SNV;!HmTfH~up8V=#*K7e&W09$mg zX9G}Q0hvYk7raVhuIG=S=(_8bqLNFsB6-bXV-6|qh+<>Tzom%riubs8%IBEeO;GAG z$lW2ba)oWb*gurCr9!iW5plEuavLUM6c3pWR@KKHG)`poI5WJ`sMlq~y%&#r^qQ&Z7bA@g&e+$8}yQz~3@Em-cuKUMnz1aF$A z6osDi32q1ono{8+vg_GQ1IJ)fzQAbrTX+To$y;A=LxEjZE9ZOg@fvENL{wWEQvYYj zTn8C_iJz#MnsME&0_c^~aU%xtcLJ(MA#077^eDuXd_K4Va=DdwSralJ_~b4L$eB{% zn&-gsKK|iF9|#@>K?-g2B3q#qZU_jPlIMfQ|3dCLBsz6ZkVgCGaz+2e(?75f^8c~- zCE!t2XaDC86Nm^pz{n~R!bl1yqEp<(##Bdn^BBD%C(0fmMBMnyIv#25F|p~vADSx zO0PkDkEEHlq`jM<*aC_VLD7rUOEraVONPRfqw$8O+S0q=tDTLu1fF|6d>8xpObBfW zBzNNvFS>n!u^WtJ`n`v7i;vNS1|3dv-Il(LVr9HPf=7(7rOA-5K>jiw1+oFLCHN!y zo-ebe*3CkY1=4sXZf;eUU*2f;*2eWnCi_INovc}VEbFgubI3%?Dz77Nd>1pFys1o4 zu?dBc{XT99LguDdMD}e6LiW0Q<%)+8yMBq)LW>2Gm!<_MT*?#!REb-H5#)6Z^qB$b zha@f|TF?0p+RX&a+}E9rr$lF5>vk>s=&|cEkY0qe>Z{R(@Dyo-Hc|7F*C4Wxk$BA3 zqTi)n*ddR^TBjgSp`Jxbbv+Mmaz1Fddo}j~$pa8^o#Ec7xtDA1O`3ZpxTDaHoORb| z*(Yf3Lz7P-avmcg`&*j(2+e(>=B@+x3UHItL9VFz`I@^S*^J274fh3_d!6RKP;T zfcB*-Oy)tC|0-#x$GYtL_*g z&x0EdsV{qwZ}TJDph335Nb-L0`~iP@l69wN(R4qMmprM|D@fhvHP)ck`E~ys$p+0F z$p$gW+A|bV??JV>U_RLc@Tnib1`U7>Mw5%dvl)NgFQD;7LLt4L>+OD(!G0#lMbp6$ zwC@7!{sZw-A_!BK4z=r2JN^vqk14=XlF>Nm7k!^V=teO81`JhybQ|c9<$561uZ!4F zM6X{=TGZJ3kr;ZDJ)LUE3gPKg$>#tz6=41ZzRy!Pq+duCS7W7v*1{(w0HI|vBzhzI6#AB+hZ7!!(`*~dt{y9AVnF_;ly+?&k2taR*qIBU*9 zfero4KO=ucK-=~Nx=*3D$ z_h*==4c*l|_V4cga~Q#4(h#^V>HaCHqb7VK)+xG@riMf6v%z>I2*fKh^@R6mliKO9 z5Xn+Cdk#X+U=XNFpDM|bQd&wRTfEx!80CznG2fYJlK_ok!z%$;z7192zNoF zr||BAMhDT?E&xC;R67;SzxDuF7lZ+@L3cr80FoDg=Ry4SxuAIgf^OMQDGC|*cB3ICKNTxezdD@BNl zJusj9U`)t%1_NUrEI^rifKuCthf+XjdB<%pW<5U0Ou{vrorD{Zu65G zhYbj+bAOBH07$%DK(+N86Vf!Mt=Qn84YW~_F(LAymnA#F^JDyVb73DD8{&LSzlkQV zD0YJE^(EN21(Fv$@YDS8HfZ3dg~&(vyTS7u;s1(`7pXADl>JWNe+#m~kK-8)NT&ZK z)zYtb)1FA^!kKii>UwdL%PpgXD=sbn3O!8i1U1@$u9eRLLggwLq zeVbu61!IHmfMua8!E-SFG6$?yAm9IMr4B{vJs#xO9piA-UI80)2P~b6PV_tgUW01) zf?54FmFrLa05<3jSOy^ZOYnV+zdi@7vYkTe8Wb;u9Oe;(0+ebtWnhDD@mfPN06Z)4 z7f`%s0eYWhSO6pWcn|b##>3|puf}qV*Fx8U=bQM;EZ$!OdFF4FIsvI~c#vN=UQT0T zY|t%U(^XX6tbrkQ4^;aTn2Z0%TfCaY0DNlj+~PF=$#=mw7JPjc?+Xw#7JfVmNxYlh zq4Uk?W`vs2jXWIP&c$^h_&%f{GrH+rd@U-;$U^~`+u%k4+#_fQHyz&McCtY`htyF? z%;kaja;BPga3h%vZtR(zix3*ICl)q4IcH+Re(-nQ?AetKr|OFP;&w6n;tZBu75mX|0G2nzlH}(OXjBl{s_}vc6oY z;b7j|12Dson8s{_2EYa*$=$&-8-JMt?&Uy!8Sa3qgQhLoRM?8p z;E-y8YTp6#pFIGZ`~Ws+0BkUtya_yiz+ayO?jaELC-_Jyrse$aVeh$&bz>BqYFh0c|r@3HO{MDZi^ ze<$BRT!ridSXH;nE+Mts@6Zg8xStT%p-(GdYHdtN2i>8Md>otd!Bc}jJM^hZcIe}G zHtSkJ_M?N8S_G0-4?G4py%^PI-Ui*Fk9>q*2A&Os&lvgy{vwc#-wRJ+K(a~TWopc5 z{Yb5lN<59=NyXSw1&Z5JRGz(RfsfR_1l!^gY_tT+?^A4^y=uNkY72J_sgWy`BI(e7 zvZ$rHhb%TFC)I63cCw|@Jd>@nfO2sy=GQ=2?Llerp_q`JY#Ef^v0$jhA3VK)`2gMv zLR{s6`P>I%LUyucmC^gjFxeU!38~fhDMf_m1VuNFNe(|D$ChWF66&C96ZD2A*n}1U zbgokBc`*Om12Dred!96a4Z1eL03=@l&u93{vpTFP`~WuS+5`iTYzEKe`0LXqY=EG@RO6W@h>!iy?Sl4& zM`IH-tevr1AwLGsQQ$E)K}XXjTn*6C*C|E79}1|o2~6?WgzrfZHX*h7;W0$+5{bRZ36k&X&(b$9{8+HxK|n&tdjJ%LT+q=DLG>k zbjaES9rDTSz?! z)#ifvWDmfnegGRZ05%Bs7fGR(Fb7rK>Up}ZWrL;+Y!D;b z(h)G8_3%W3`ClFYyD7uiMjJE$HW*3%9y}l8&p&JgY}vR7g6bgXQxK2(G}YkOmZP|DUDE|V=XdqO3P|UUrgJMGITQ&;7umFFmu3%(Hb*#Z|OoSReFlJkZfia=1 zTQ=%}viSkjG7zp66m2?|nMI^2I~z1*=h-jw1ONsml_K-w9suhpa|_=r7xmVlRN-F_ zo=5T5XW>Ui!5a=iPk{JuBFNZn4QvbFh{;y?hX7?zBX*SoVYkmxRcKsgw(xx@?tYmM zz%&d@80!hsgoPDC6&@JlDzk;}gUQ@4^PSNlb?rI~ctD7LNo8bMv>RDAh!^>CQxk)v zVusqF-Y??@qlb^eLXjsh9SN|(0Fy@@L$5Xtt1 zv!UM;L45Zv`SY!s4j8S?4Ql9ZCh2ahy^{o>0KJI+xq$TR*>b#gQ9t5$Q9oulZ!@d- z$4ywa($xJ2I{mmAry&4tab^Kv1>b@90C(!`X9`k^zzv!$LpIfYs?a+IP}TTTb*sjN z)V=HR#y>*GX9|!K-suO%=ch~94H|fx8tpv@0GkQhx##X!{?Umr)~UnV{-ztUR7*Ccu$A& zLOm@E$2WKL{l#KulEihi>$f{6JC9;hNWY$Ik0+5i%3ckcB2fK$t~x$B;yS#Rj6c2% zxtEdKO;?AC9XOQV9q7a(g}S4F%JcD0Kt8`K1*YvmjeoqiLDv|&E{B%@FnO&~-vjfL z9)L}L02_3Tu>nZl2%g9B*QY%w7#mV&LeQ^4{H_Qx_Q3l>&XC1AWbB^_MN<3c)&gZb zX7BF-VZ?tt_P~eI;zKc^Nbg5r+6_#q?pDBD0ho~p&Gx{2?t?KQYm9YT#Jnqn8O?w_ zLTcRa@rVluc-`DxKsAL7jO_M}G=;Pu$;`r=LgeEtd_H&@@TVvF>o6(wE&Q86R^AL- z50bMy@W=Y$kM+YJ8zLX!TflP$;boHlEsxJz7XG(`Y$M>$2Fa}guPfv(qr7Z`8giG> zUEGF4?jjSg-3o~b)E9^yy5=Y3GmlL=70Tfp!f{*=aAG7i3CV7-W_ z&jd?a^pKghK}w+_XwbxMh#>i>nO=G0>^afw0>mEsGo`iyX{O3^t7w^-bh_iES=8&{ zZkdsV$;ws$EZU$HnUC}USkIO_UituRcZnpcz;ihM`s^R`3qoodHY}_L@$n+a^bZYe z$4eu|jF+}a>i6Z)Bu@j%idHzSfpC)t#dtgHc5;N@Gvm(o>oWyFwG_p%rGz5RtBjAVE-HU0Wfde<&}1uP_Q# zo+ZqcUdkusdI~eoKZThuz_L*{Nv4~ifu5!uVWufJnrTYCf11*07_T$alqM6tmJb`G z_AZ4^BjHA7re4gFv7IjPwG;&TECGci8AFgDaxkPozKl?8D)#sS?$-k{%j)+#VdL}l zMp3>1gJ<>EJLCeSQ7aM)sRm$>|D$Xe_gD-{HeNg0P`+j&PM1~56tI27!$JNyH!T} zX<$s>0m{d)Uq1rEOM;>&S4|-UBmE(Bd?z2OJh=rtFXGSIuQVs#z7sLS?@@}-|M9>d z>xZ}Y%S<1R4Uv!VuY>0c!u#wOdw@9cE&$mZfLA-^<&Vdob*A5Cln=CDWCFHZAsXsc z#Gc=ay=H(};(>bJ2bE^O$ONd~VlXVmpHZu%2s1eBVmbg(t%7Ckm$y(e$9M8kGg~`a zv!f7u($Ddt3XpD0p+%M%uZKIn8wZ^o-?c1^?=J!14^W59&w2o?)7l;1eE_z*M3O%O z&(rwpvwsv6ht#vMFTVxxha$-I4-IVlhY@4OccZ3T9d&Dg((h=cJ_5qnfvHM0o=ZEv z`%v8eu@y{Xz=ZiPU`Al1+XJC_9vI`fwBx%E#`Km{4b%r5R1a_e^tBes9I<2(5Xe<65&MtEQU;P@{6 z<93k!7VwXOHE4=SyHkcs_cE11TB z$*8qt61E+n6Yqhjd4gs8hXIp9&FmlK%j_Sql8~BOnn47 zCkV&)mmuP309`#8g=)t4kH6GA;j)bH1lHp_nZ`nc9LIOfm>S=8SjKm$y^YW*j7LJu z)B#yCh7sJGvCQ$EATquSpNBBd*(?fV)XXRif8?;t~>@mP^0?Fk9Z#t_{K5#H26T5_6 z9cieW5!?DLoSg%hhdofw`=HV~E13Y*do36q#Gg^?Q$&9RtVa;_mSEY=>MhjF&PqON zW?#kAnjJDFq~<-3J>)=|JdBOOR*~_iWwEE^qrv+-_$GocOBLM(va3(Tf$<<|^}ru% z{b?HBR*`E@$w&A~@H7zKS4Fg^Qbo>GEOJi5Pz;jG1>RJVRzBFCk}0!_mLhillTk&0 zdDsK>ybmg^ipV5Y1cnFkXVkh9(TARbDnis-f@Q17fMv0#|qR!f$lIdY+kfS}-j46An z!(vaR_8x^U?F~4f6p$Ze$ruc%E;F66OnXWYv8MvLa~W0y37kyH)x8*g|6FgEnXYY!JI`z_S5=ncFRPpB_?|J&OK;)Tcejb^hI!HfSEu*&vo9 zrvTt{sP+t)hmT2_hfRI}8#Dkm7)`zmzMaA6pQ;AD#Q7uyEjk@*Mi8$QL1wCI_LZ7P z?mA>2xtmR)#@KS_%Z!lv%^C2Y0O48>N{bK0gzO`CgVLJ-!zK8`o;bjipM?ij2)*Wk z`P>I%LiUlnRYo5b17)@X<(I2)vL+CA8|Stod+4m$B55GS*E#ev@}Nz0-Hz*4@ZGe# z?WW2c_J=K!jNAo)x*PVj|DOW9TO@T@wn!GDdDTsw8B+gTfkVxKctNI`uqS%|KgeW@ zB$--oLg+EPaW-i2&3J%u;mw&3H*QD#*@*9uLmQXq=|o5JWfRT4j!WOdRDrXIcM!P| zwA|~sOjEY#y^aTB8~_RD6zZraA#~vc2>k*5(->5KgZJ;6M zg-Wfv6G3dOS@(0f;(JKLW@#Fx^K-EQG)K(@&AK8y@hH`=KFaHM-Z%A@gMdI6qQD-O zLR&WuK?uV4FHPDbi2vB1cGNjYJD?S(N)~BgnRI!9Zvp`UJ^^EO0UOP_O$Z9`FHPD) z#9!b~i~R;;_=L9h?sc8*_$Kaxr?KUnOd za9$f9f$rSjITNMNmw_B-zXQ-eO6FbI&yCo(KOzYdc8_`PG2mE6^$KbWr^BEYyGA~SM$-0 zF27bQXMTLasn0e_+{eljTZL5E6k=%K#Rt@=;Zxv5Q2l$*B@&AdOi0|tBX)KMB$`_4 z@y+HDgPgaSsR?QT(>ohcZXNiH*oYxcgu~B-a4NpBtwD_#YU1-#@jOyljTmMU21&xk zPJD3+nXVWcErlru;pO#JR{ypWGH(FGFSRo`nRk2VQ0 zO<$kf(9>a{#+any6pvu-ZsJP^pu={eSD=jcaIVMeg`o-41|(3p&24H#fpd$*%tSdh z1xD86E$Z*qP?YoRo~Uvtwt0(m$Hf{%m-XgCyr-s>1hRKsdJ6g z#KHlI-tPJ}EsZY2WakM<*>^xf`V@!#5mTHyM1}nZB-nJ+i0RHl60r!uYjv>ZG=dYNfqJO3W3;nB+nB@!Ex>(uCjPC{4* z)~L}d$g9BBTi?>ts7BY`hA`Tn8vHNZux0P^Ff!9m?Zg}$2_b_xjEKQ6 zdShqcyb9zAg*yCD=6vW-j9U%Ov{w1i!4&Dh&c;?1ZPcN#8afZOEtYtL zA#M?KF+pkKRviLyD~SztB)ZX1ZxWMfsWZbKqlP6XgwM^%jT%`j#d&zIb3N=D;RI?ByXj zq`k92jW6-U)H09bOBu7%A2D_N!!FqKF@DCt#zZr{t!n&C#KAb{)GeRS+3iNzX2ji0MyN)gkw&ZV2DW2Z>0 z(9PE|(q{c7Mk<-=S_fZ0D-D3B4RXg2>dDa)Od&T1y4eVN%kezMg7i%>Y zV{}0+(J^7hn7kaIqtLL|CF-RDm+CS>%U)+ki}A~J8K7;i(`|74fp?m+L=5LRYW#AI zgtono3#WE9{vaKL#;vjITbkFR8dhl50!F(n@_QaxFlyLy z9ddboPr1CXzg%9tjF;V#*m{Ob1IM{hyEVNkk!wGf%evwFF|v88T-NU|mkkYaX*o_V ztv`@U+v9TSd`B)_kwxU|nI)IrZ^&iiDRS9-ja-htTQ0{uA(vy{l*@5jsK~a=D{$f3p8%kzBT{lgpi#@Ur{t`{Ys; zTguSh`|`3!yt6+q)!&lK!a9lEclt6$?zccLi`K|x@riQT|5~{$`ITG__#e3}4IfB` zW#f4%*zW+joX2U@sDcZQl+cA6<#N$wa=G{cxm@z9T)zEqg<{ZfVT=q z72G&QE;k=8ms?Jh%a5*;%Wc1u%k6)Y%N+yp0^z8FpX?=d`>P8eI}QO_c)jgk1UkSFPr7^tCQsN z=uL8Y>}k0?{)t?k*nJflo}4Y0rw*3O@4Dskhl}O%$1QSs>vy<}F4)QWOs)f+(T6a+ zvojypF`VagY{udvxnW~{XG4N+p!$|M-JLy+rTm$zoH53Sg=vd3roIJ}(E9H7&N*Dq zA$9k%2==D7wAXX?LT=1-H@7sZ@YEmT|JW!D(eYzzc7Y)p`vvZu%ow%DPXK{68GK+E zZJOKG3U(=sSydIK7ej1}2u`IGos*dcmm1J0ytx z+bQhA>qkzM(a|_=@o!9LBL`}X^6+Lz?zF{CZrW5;g(DuNP*RD>_O`C>0;)Etv_RC% z)LzGDs;}cS^e>ppJbYC>{ueYzY36lbK({^C4aNAh3LhqK@07*r94|q7wRqDcYvcAG zgr!mb@`52}=<1p97ewSA^y=vnoNx@9Nd5{P3QuT5Rpr;}Q2uy_y!k7g!ehYeL_6@y zO6wI}zM2|ewS=Xny_vB!9wa=yZoPacgzc(hFUHrGovK~khV^+rlUTirqiNOaqe!n` zU!uQ)Z@<)6!Qa$DQ^7i9D_Dm-6+GrL>6-ZURIpE0-->Kk6`O)65Ls#E?3bTj$-dO> ztz{p`ju4-!XuTS$UDwbl)m$??t(raQ>1FFl@>g;3jlL>=?*?xl)*)NPI+P!q0=aHK zz7YIQ^fdgcJ)LHBZpSH|FbxjicMrQKJocMo!4t$Wgqkq<7@?d;bc__X@= zq~s zu@C4mWyfSItwrw`(2V}DV_>yG-j32`n8xhPTXS;^f0X3I+N=BAx`C$?q-=(dX7TdnWz$l0 zHN7hnwKEcU;Ely(kMZ3)QBF?u&sr>oRnbo4C~Kh>l`iIDim9}z!2*y~7gH5=XN4;* zNa@BbY}poeZCS$TkH`HhrzL8S8DHQn z9xr}I*`y&uV;4*nofwQ$T3{iAO2i@tm4=HQ<+Mc=tr$;5tGRgV>`8Xd*)cua*sC3| z)>i|UN}HXQ(s6NZS8Z2K@A8$26-!XZC@_v^(Ub9m19S_e5BOa*>h z?R=XfS(}|^P}p%7FGnWPevvS~s2HIV&>z_Tc9zQks zS6gmdZDpdiBB8qfhpm>ssUKC;u_wE!9X@tU^FdYyuJ?})#!i@SqlyMkq*$Nr-!ZZ| za%_~|oIbcx1$5!EMA`I2LZ%A(DWA6|ZSi zl+Abucywa}_r|m&+GHxRg9@tDw{>g>4itm#XZcSr=i~6;EU?Y4*SUvX#o&>xQci;TC|}>&v~i(JcP|&i{@q$C+Xy zr_apRx=dmETNfvx(`6DW1GZbLQLfch(RWHRtdVPSgC3^rupTHt|96IN8umcrx}8Im z803mfgPa#&&g^9Pl8nSV8Rz0Mx#R{-(cYw@7s|a>KitsX zgSVMfez=4?n}LC|U89$za;Zw*F!3!adKupgaWrQs_dYvox*F^8%nRoZ_VZ{auY^!D zQ7_7OPgE&4NjrG`MMX#T<3?*IDjDF9n!>HqPE%)Nqlz9Ja-zgirQAsEtZnRWYy;D| zAzdiC#JIWI;p;IfI;J1@YdcZuCO@i_d#;^UDt`Y&9|Cf zGHp!P#xQI)cTkqy?X5UpFWPAel=7oY)49kCkHUR~rCK^ybC5wrn@v#)J(JaN?pt@) zfNI#)6S=$HsR#P7oA6R@%6~lraW$LNyP`6G)kN-qcUoG6_!b}WEQw7c=T3QPm&0!J z5zj#Ds@b$jakIS>CA9pgiM!4bd^Wyecx35O2KZT+#@*9_mg462j# z6X&n}APS>qpa{>#-5oYOV}rCWhhC>=uo_+pljH5$PP&ae?m!X#-1&AY24~Ml;?JKi zDRUr|>alxLIihYOhiN-Dz23j=kmApz@8Nt^AOq1Yu>DR zl5@fLXDju1Jt$8$)t@07n<336WY3DF2+D^|>l46-#Po<2mRuJhSI+soKg! zO^xCUkxq1dKYX=FY=I-jOlsF zc`g-}c(+POFJ@#h5SEwIR5)C6w@cT8Rm1HP^b*P`E@o9YC_IJlgF1;CSy-NimD$@6 zuBLp#*d&gv;gVGie+CJR!kU9`la}zcQKt##5#WT8;lCk^NiXG_q)t;KmZ8IcYnBkg zSju-xksu4;;lKALmGFI2r>Uu>r)!-W{yQ%kUqN-6utH3#;Xl!9DXmB8H8zDOPz>MV z!HY5pit>He(#I_sh;}gxOj(6ciiRrTE3HlwtYDiO{()p%7nff8@J&}PToj#YqTvlcJ){?ZqE0DazvbE*CAY;}a#JM|OI|hnUb8yoySa=-8SUmNBQ=F@ z>pB=6=(HIAXS4xbBz$|<>A>-6YWQmg+Ebi-sTXVA*7jbsjmvax>dwITe32rrn-9Mt zm7-y%@cmyT<4_Y6^*Of1P2u~%4vuc&IUmFK!rGYmldZO@lrIT0tydDKc=DOri>ueB zWlnc%2TzMp!>^O7Dd8){jD$LB_#JE%+O4BX`Ia%B?dZZ=Y05v9!&1I}>~ytt;3dv( z=u~gSO1lyt0JA$?mGb>$r?;sqS>Fb-tG(KhB03vCs+6xUJH3YJIz!}1=X=dacf~aZ ziZft*`x(Rr?Itf;3UVl4j&8wV->WLe&KlUzm~6(|usAsd`B7slnGZQHWLw5X(Y`^7KPX(J^qrNUwzz576P7HoaO;X^#lN{!uL#}^E2Yg~(S zIo$XqIzA>UH+9x06AjI4amtt)djOAy3E>bBU+hvHyVt;uM6xS^!@QC>oD0+k>i9{B zN9iQiAcGzC$woEyAe~S$u+7gJB8$_*dul9RM9?7 zqdJ{7&7}E-tkH>Ol9;AhgHD@n()^4~I&p?YP3h9AQ)XJWR7#spnWakj`aSz6AAh0i zjr}G|-}nXD9#xs6lcX_@J>f9Y=Y`pdhw}CO?p9Sg?&N{pc-@*u*_^^oC{42!-~MV- z<4)BPVN#&EbgFTu>6m=Rv^L<#=y9j(m_ZVQGfKvtp(7%U*o+ZQjXP7vL>aSDn9kBM zBZWp{&ek!zGp4z#0S6b2J4Z(qFludUH;*zIcRp=!XhMu}N4MjclyMg@qi9#is~q5? z#@)%|2%Hk0H~_y?QxlKvQRD8{{ym;i5ao|5IhF*i8+7u|8RtY9hY^5B7?fPWbe(#) zPGt;I87R4rsr6kva0clA)+NtK5Il%WL@@qHDnldhkULREf#xmJ2olddaF9U(dP}s@ zL?t{5LD!&8{Hr&S2PAM>WAgW?9y_Urc9)7l5`{wWD)Qhccwt8;cyv@L&rxu+BX;ye zhi5F9nMvt|OyQIOKHAYg4Cy3BLS-JbR?0&cG(ndd{dh=x!BKJIz73+Nke2dD2B!&Q z7*XyqDD+I4be`3q(*g2~83M%9srh+`gVVGT$K|Nei%l|9j4PFgJ0RJN5Tg(BQV<1$ z0}p-xiMG_Ej}D;VnGhV7sp2i(jLHx$ZfiCA4xLc?6B4(s>7+}1^jt@mwUn@oNK8fn zu}VsLtOQBL%{_Xiq4m4DqryCTYNES{FonzWFhFMt_Y^}W z^=Bw}RE8eosmBXO3R{zD0X#$lgSRWIA-#soh|5zpNM~eSl!c6^aA06|;p{UUzv>2) zXLXR+U|yT9zaisU9!{?dxxq`O=N3HX0~7}5icA6?00PH8Dh_`7(Uqp&q>oB(kY-TA z^FiqT$Cf2E`dq5)=pMzwR3$t&M3P%O)aY-smpS^WfKKLlB9hGI(daue(s|H`q<3sq zqfgC1=K&;=+|_}m{RXSq3t!5UNtmw9%;+)Rhdpkah>D#l;qfJ;m0t2;3QCpmL=&d8 zNggju(?ZW7OL*RiCSp!6Ps@oR;%O+Fi1|4)5UF&%A(Dbek2%;|@=Wyfn7lB{v4rQU z5Lb%ft(5Lk)R+pJWIihzy~)vo2^phIL3gDhr96&>AQ-IF=x;iD6`7(c;W;fjeS;eP zk96Gysg#GfXc|=Ksg7QBxERI)@`x8rgeOj;&vx`9r!=Y(o&ZBCdA2(Gr#e%V>UpYE z%JX4B)ZLC2I?2pv*-=#~kBo6P^3f^lV`q~lLga^ds+1?nXew67u1kML4ShtXg>uf}mZ<{_Sb2g}b>Y#iGsPw=Ic@Ms$r2%iOyenx95 zS&^q^B|P$m$sKDtQ9pn2q?1UM@GKmr%Ug=0f9FZp{5&Lw=@^yO=)ZZAg}sz#=jf86 z`2Hqyu6*6VOL?*mLE!E{Q#;<#9tNS(4TMMT7y{J&#m>7>&2(83m=?m9?KD*n?ZTCg zc6+!unhdXGcwS|ka3sRs7cnNRo>_mGQn&01teszVrkS^?5^ew8#q{4@OgZmj!V|ci zU&l)VIH-I&_8nMWDgVJHnEp$U>m{kD?PW83PofqlYbtnTA>N3tSz+Es zKXYd47^Ghb(ltbSkvXgNdCfC5sx*(;8*A1tU(%~zrPgI3+a{tP^@nDa?-H*P{_y@s z_JLP6twHb1zzU>hd2&4zlakdgq|*SVD$1DWbBR{pS3WD$OiNXl!rb1JKELmx;La8~eza^Uzt@Eu<{uewT3=fyGKXew3V z7olN%c{bQz!u?ccuhOJMouU~*LvhV@PrZzFek-XX&ZTZ>BRADxOw4?5oopM zX!s3q6W+6OZ#g4d=8 zZbm{mBp?C;HUT*$;8a80yryw2+#9hmhJH5absSjsoa1G=)3WgV?ASO@7Mc;0PCoaK zh8&*#4JtMvl?6tC+G?-%8Jp0VO|EOi`PQ*X2DuWdNEAC?QX06`U-v%tY&EyV%bmb< zdu{hR6`O8A%4S&5c) zos6wa@iAf>d>0tL`Yv%~#*WmSYyvt8yz7&$L@6Zt+tj>&kn_*zn6VDcgTo?f^xasF3K7_pmgEc*rNPV^Oo0J`0nk5M^Op>%oP6V#OIHicb1F4DH}fY zOR>r#RXW+c$6VH9v$0Y(-oy7*l&;_bYjg#-_Q=`gMGt8R7PyW=<6;e)ZY>4w{;0Wg z3_Cke0>#{*inbUfrUSx__I9rM&ZQViVyC)vwTZ^oj_%FIC>$q7VL>mEuV#IIF~CSy zvGZ(X(a)?#a=K&eMmOOun;@qu#GZ5$9`PpV-YRW1_MuDibTEmw=CR>PqfyaImd1X0Eyo~qM?}C#PqbStG<>G z#Jkj)wA7}iB>VAaUDChk;szPbd8>UeEv;AFy8jqv>Xexi+@e zNLTSiF4;gneuj1~9UHtIRf=0lC)Rr?>1w-XqztzOE567j8f(A|l@}_0AF1BJydXAF zLzQ=0)%G4jky3~%{%4nNszFN;@|04mTYO+60=KcPR%*bRc$mXc#RpgBQY|oWmdpos zD9NU>+!k9hp5YBNJx$W1Z1Kq?vm?fVRzDq)MjQVzX*n&6tu%z0vo8%>{TfMEp~)0A zlC-v~9J5-AhcUG+#%+tLdO(vQkF}?f`>0iXItk}6R~xMg$$C5r;x~=_IjcT`q}9;2 z=uO>lDxgARCx!#gIrXeTI%M_nq}<4gyiiM@CC}mk=+@y4B&ny|%Z=PwVnaY9`xDHh zCH@TQ2C%E#Xy}?ZK^`ZOrkeF;?S_;N6`Wu5cy}mmLuz0a0 zd_&`Dx(vX0H|egUhX2rn9S3CV%-?ZIKXXZgJM*tx%8+~%stce&o%s{eoy}&kSl3B; zeFt^|G-T6Y`Z`O0SSCHj39nh90rHsH_*$2Dik}x*@N>FWRmHz;nPO9PMy!It`F`Az z7mfAHKr{F1b{dAIhd_ z5xaceR@rZZ$xu;?DQAn2QP9HgX`7XnH8xzn8j|g_CW~QurEnD`6jDg|5=Dv#=eq3pUx`B}EbbsQCUZmZQnXk&_-7YN+`4 zT)d;dIv!{1%#AN+j8O4E5_hkik+VxQF2PqU~ zPD$KW3{wy+$<3XLPddux>GBk2`mDbCo{oU#lI&d zy`n1ifgzm9U>aRKuM2elgy`63hOBG`cA%tQYy$)RwJz{{GT;lY@Ou2p=8{1!vD32Y z7P8J}aj(l7+pWJTAYrA!^p}u3kygb&OmR){aY_Api`A8M`s^LyW|9_P(>a$zsGV&7#7# z^1Q|6zBvnb_RN1k-T|Bu-EDcNOXgeZbIALwUc+5fVDs+h?mO$979#fhUL-XZ#;ztsIPue{5MRJhhHDXDd{QuqN`t`uBd^SB3R2 z6RRY?{8ilEhNMBU3;0ba>p{JcDBLrRIO~{Hv5RypzL(00Qj`8xZ0zC$_(K!&Rr$)} zl%j+|vC9h12QZ)f?t2sGB=eTQeCkK7`##5rg=P5VH(niQ-119Irn+$B#;8u2XiPTe&vmnY42aW+thn)qmnxeHHV$b3%# zvrbE6E^?05lChu575#um-x<&xtL#sH&Q^^EW76j0eT0GR|R!=;YR&cx_9 zbwR8}MpW!~DJDJ-XCyl}XS`fycsOOgYbL#i3kK%NcwY+N0WOMg7G!FEHs{Y0uiXza zc}^*=yQw@TD!Rg`f@iaM8v=#;S_($8U=plGHWONly97jLRc)Mq72)XBMAKI@Mq{ zX!cC=vE{t*dPGFnvq$8W^rGX9C>|%5y$X2Q>7f&pIuN6JWYVM%j5uG)*>eu9#G=+^ z_1N}5spNbBaQnleR`V{pnpFBvaN*m|h{LyHxsP$uWcfJkgnUHBIhmg{<=_2DGYAnY z`2pBTQ+32(MAYI7!#HEu#hWG{pPjHvzu5faQE=2}(oCoDUy$NNzrb&l0;3cWC5rs0 zSkfh)Wr_2@h1A_o!B5Yr3I~0hM-q8mY*GcPU`e??4PhpuQ24}l3Rwm)0uPcFZ;5pC zJG7H3J>(T8793Q><@kggcxgjQV77;$Tu0VmzbSM!^ie)lQ4=Q-p}A|nmi9IEEoxGg zhpo~^Ly&$1V^mv39{D`%q`f`#GZ_V1t~y+$&LVAZt9&PR(mo#Qavd3@)MC8mffEzd zq9TDDhQEPR38&37XYgOTiSN=+w7FdI?bE$CA zqxpAQlt+=XCc2WiO- z62B6p`yIGag-d5YM%F|7?f*V>bnLz{zD&es0*)ytF8#oK*0mD)I?{y+B zd=1pYJvGHW!XU`KMshguKct2gks>a4(fQpHL;;(nYZaL|Ol-foslhe1+aP_vV1DxY@v&QxesW`j8uPR&!*hmq6meP`6 zhq3C2(o&k00{(C|8T$q$Go^H@Qz%U5kKSb0AU^4X;~+#gjP;VoVT#BKR{ z{5-&IMgwXK7%jcLitWMf7A6JSWUU*QbP6R-f9y83TUa7fjh-LVtqS+zH^SSz@bICK z_sE$_y#RTG@|RASi6v+LQH+MviZ>{LZtQ&S{a%94W=;2g(s%KCtYg;K)MWa$iS85< z7;0{1U=UI2oWiFWr`3#&*`*aT@?^2OfRbf%s{eOgSa?N~=M<^6$3>4sWawc@T+ zI~T#~PB&pKpJLQ(rZ#MuJ8l}X(8H~19Ey#0iYsZYHL5aZSJ)X``vpw;h^llxZkOJptR9>8N* z%gsI()1h=G-MpyygtNiVJ%9O21Nq&peY@`CidON%T&`8*LPJc`*kx-GwpXaPDn6HN z+!2_c2oz?v{&__eKkV|X3l?RVyn^Ce$;ADF`9}o`O6>|9H_Vf*>E~Fsql0Co_^w7< zatd|6;%mvr-Guok1&Xt~27SV=c9~@RKxP?QE}y91k&Al`^Dhimai(wUp;2(~x!|H9 z&%ZR7E7N>y&g!M)jSgqZZ^~gJH35XpW^c0vu%F2U5hD*|D1f>eVG4X7LBdX z50k#l=w5DRd_qp{AIyIum@{oVq0VUKl=HyGJ&c2Eg1Vq@M`J3ND&9ywPRH`!3(TNw zHsrLy_FJ95t6jD)g0&Pr+8dKGJtWV2oqV4%cm4E(xb&Wg~a@}0}RI3rNrtfo#Z2~mq4kt%+_%e8l~ zIG4>MQN{mBw*6Tf)q%ohuBlJ*br7Gdq6;k3l3-bu%PXq7fn3~On15KHD9>g?Z{Hw> zs=l1edy-l2!cDJ)%8quv(<8c?hNCK+3&F%4dV@LoXV_f3L9VaOHS4kRsli-*z492^ zDDR_MxfUxY|AN4reKkS8kw>JYhM$TjDT;g42Db%e$?RCmEk_yIQ5DlKvhYWLZTMR3 z2+1fgMyToy6vK@T`L6~RnBC_fD^6`ZIFhUCtI5di(D{E4Wc2Kg7B;o~ZF1ZRj=?_+ z%8~Sb`97L=+=l^3nJit&^A6{bd-qWyYkYi`yi*6RsC6@=A7AS zQQSw<=dROKEA~s1CX5N-bC>{Dg`Y((Bl?!Vc@k0n%}bSfniCVOEkl>!YS)%mAOREP zF>V~zmJ%1e7AYz=iwSmZDG7E4cREvYdGU0)b@qDJnE14tc=C^^L!+J9XnYQlKYU(o4{kT7Ltvs8!IjlQVxc>DgwB=Gw<5GrM zfxbxGTvnhd;LNFv6soG6&eF(XC7Ocru1KLFTq7t{pO#XpIju@lsHxRyIvgA5LnrX} z4Cor+ZIwh+Nkm@wPiW3n;p>^m+dR1~A9$HkR}Mqwus&t9tWRHJZteP%6lm8Ux^Y;a zN?bI86qQ<^N@Qw%dOH~KJ}qb>yv+;$3u4MozFeuhaFbe}GMektvnXd9>r=N7uujF( zwxE?N>)P+D^;B!tx>WQdxfcXr7Eemn@%A{_LXX;eran~ z-TYGmx4CA`L`z@2q72yVHD0ROqoB`(qLJ~)M_!n}<->k}#}HAyer1HLUms>}?D~}y zws_ul6R>{O2~s?4uBHV4qaI8tY0%q zK(A!6aWqD4z3|l!6C-FPn*rik)AEt6g>iGJ;{C1!R?w<81It~gz9$P+$(4#PbotZQ zx7h)f&1H@zF<+|qL;?h@bTjzP^3^N8_(7LDea)MV-77pEx(dRBR=*kCsr78$Zq(jp z-vvlt2X6!61hh_@|M*En2wD+m0N7QoPl1PB_Vl%JR(_xOepf?$;3_$j-?v`Y)feB7 z{DJG`4F1gFMq^Z8M2w)7a|VQG4ISK`tDkeR(pJ&gv21PXfiynqJJ2R@J)HqjnX$4q zrE(ZC0$0`<7-?&44N!R%0Rq<88SK8*wzfg+-75Yn5rS6R84$95=0wVC9#nkXH5MR! z-5rcTi)mW5S%J3@A#eqrfe^eFm%`9s#kUeHU@e{jrB~M(`6+(i0;I3Xvmj*TCqDIB zs1US1&p>dO+#WSlyu;;BU#VvY@MxjpKPEuXnmvQxuETxu-*?&5SMOQ*z2d7YzYFm} z>-Y?I--_PbQ;DalHxejlO`ieeU)^h?Tk$U016KDL+_^5lp&?$;;7XsmdIp#%@1t7j zrtcZ4>1+M3Efy<5ZyAZq)DT_qECmOw{4?a{=mW61&B&;#SonP_%I^jEx}tD2eTFnC zTUC7;MFx2UGGtoc0Omy2QgLpisvjmqkZ&LZ!s8{-ZE5+)>%be}CCFe+t@2a;0@fPV z)G4#8o65W^2^!=v*am8jz5`o%rp>t0(;7{n{~%NPSM(%U;kv#0WlJZ)9Q+c@maD?! zP%#mG%ilbS7!lrsTh_|oyFsZfb5TTaDjdRDpmiz?xe)=JUE;>UsUUID5lB(7GnrtW z3X))_)o(B*C#QmU-+W{SoWepX5zV8(irLp&*uESKSzx7OZ}s5rEV!2tHy7uE z4>rxgpw-poBj!S%di76Y=i*@SVW&A6^lD3EQ;u;mEMQJ@ax(b9GiQEM$g1)h;^pFK z@WJ_<4f1xStZh8nN-5{&Z15p_91dxaY{T4Dk{5n|C;lqbV}ub^5?v(`dEpAQ!>aID zCh|5|&e-q?v%kAJT4!R!b0MC3#PFYSN#X#wC#I&x5p^Vc? z$M$g(;Ce6#$c#xngsIl`AgQ)9-^!G2xE=y^Omjcz&XE$jZTCYUVulN%Ok5BeGu0_j z=!22z$YoOg{4Jk!mr^yuwF`m~;)2+hC1YI>q_D-*>?XhkVG>wOY{aIlPIO7&f=H35 z*p+SqTo5{88lcsJyO`j*ASA^W@0UypazO-@f_6i|nYTAJ_KK)p_Cv%3x*>vqysilG z?x(ULIaTosi5KXK2*PvS5zlfY(Tb_~3ob^6J7Sw4CG!ZffO%BKqi(?^&?OOsVcZg4 zHHwdL5i;Bo+ko&Y5&teB0$me92r2i(zlMX)7RNg-NQQf2+bEj^MVCi>(yf3DbWsF> zST}`Fkv111!%eX*44)cz5F^-C5s2Y)SD379B}TBjA_yaM;Lmmpy(|ut|Y3z@I6YRbS!bx*sXpqVzL4sTuK@dJS zM#?g%_>DvfbYld;h%19rH*2X*gDq6?_gs(+S4LJ8T3<(71mn(_cN=1Y-5EhB!7dFc z9OKeBnSenqjUYJf*2u_P@e>v#!>y4WB_nU~U2caefv$}p6xY4sQAfpVU5pI(#x_Ab z+Tg4sf&{uaf-tO`!>7kfE<}c#V_O(rHL8p5fEt0WjvxrXyTjANiK(jB6D-i(5d`LU zc}QPS6@Ml~kjo4a-ET3Rk7a|D=y9bu>-`_Rs<9=^Q)@QrPx3hNRV9X29XD>+Ej9G zrmBBKm_Rp35RAtaqTAT=qC3GKka&hg)6N>2We3iIMjnlFSpIfcWiK=d=*tBM6b zwUB-JLINPQW7UKCAHlqwn7Q~tT*x#Zh*ndViP#O}10ilMJ`fi-(Ep)vDZ}_b_F)ck z@_)F%nNvt9R8@H?v2yW!xKLUA9v&^FRCDutxTxtqj}#mm=wF~^UYKv}!2f~!2qUT_ z8lDeH+z)N7Dm(;DCBoZ0xh?NOxMKve2%iU|#phAO_GGtOkOHlHwHpVYhr~sXL6pbm zA(1Jc$L>hQ`!D#7@HQ{}0K}BPf3H%f;wI(uU^IOmpMYqaJ`Y+jggfL1s**-e1ILnla^l{*Da&(tI7d6Ql%g+t-nSmc`GZ z@luT+1^qD;jhroI&foImeuX25MruC?BgD@!K)*&hzwv2! z#TS=8V7W7V8d=!A!sD%E5APGfmfDB(oc7%fkLFYgI9uWfl80i4k zhv8FT%Fir&h7ThfzfXJ{`Gfrz8T>xqg;DWfK8y7B zTs{Bi7AxInkrm6sM+o*yc)*HB zJ_xWNzeGBe_DN*qr}!`nkl~XEM##ud{0brj`Xka2TwjDo4HbXc<Ffc%2i-P_r>g%%pg`Y4I*{M*pvRnw zLmvivkl!Jld;5G2o&hGxdp%NCKWn9C_#D2jSl8d6%SdFplMq!g=MiK#$ls7I_pACE z(le?me(Z`$^EG@;QS>vUOOvuy)gMq~pr0XKrq9Qqi;8n2RXydGfC%(4q(gZ83%V^W zKZ(3S{)KebZTJ?nE~y%u*Pm0HK;J@k)a~{w1U8yrze0xeuj^Cr$d;as={QeCsS2No z5{T$q{$fKkBJ#pKW+yNF)Cv6MIRYzq5DJe(=`Jqfa?U-4VNq*M8xAzU;VH$%eDfnT z;Rt=s%9{2T#O=lX8=(p7`YjpoD2kd0#idRm(HwJH!$Ky=X${5G@WRRr&|m@;cu2#o ztS-YWhcry=A~Vj3(Hh8cHw36KQFsH5ukSjAfBgu*YT|cE-X)(HhjKjEL8wg(sP%Sf zQBPGqOKP61Q9R#JW;s_w(=Qv#Ts5}hOSi=b+ng}yKW<{h@^ve)89fx~m!6&IN6<35 z6+a4RIk2o8Au(A_tzj9PC&%XCQ_ZLHp2uZWNqtp?nL46Gj@+pVuZK>NM(mpzQ951@ zekz?LyJ+5c0!M4ihraL{T}{31E*d6anR=HS2d|ODMc+Y+iao;w>ot-DyJ8yiI8t)) z8sQs0sgJ_p6b$`kmJcX6DhJb6taYLK@D}-?c%p`UtfNq4$>Dz$cM~fIFA<>9+(TL~ zo%z#{cXRebJ{8TuJp{lszYtEPwS`G+;}%*2K@CO0I=LqV8 z3!UeX=v<0cQfxW7fdJ<5|M+3pD!+-gQWbs|szrF4C%5GXJ*m{*qo6K)JB$|J&Ui$+ zz8zAa4OY2v@a;%k^bkaOd^-}E>KC6vQdRg!&_sBf7hX6Teug`KtwDh9udDjbWmFCOQEjA@+o4%YBN`?^S6BG7nJ%j3X`Wj zFhX27|D^KPg+mHk8que00$eycK}v%S&J@^Wmjo`H6p4!M>n6a3qZ5VzS}mw&g6qPO z6kCc{GbzA@<7V7F?_qap>4mL+oxDM=8<*MZvSHItX)9kaQ1Ow!0Ys3;#)WV_HP_E~ z<*WEXE?>H*CX?}w1!OFw`l|ReG6s2QTt4HO@ro<{nah>#nMr5!3XA`XY(X9wmn-Fo zIdgYvDFvkBWlvkibWcnG=QqZXQ|B+fj+{Xr7?;s{UVH+tb=lHAFByD3aW9fD(BqQg z^Lbi~n$c&#M|+-e2!zX*X~s2g^ ^02t9Ue8KUv#Y+qg-CO(WJ1_VF%Ffd$QkHR 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�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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "elf.h" + +#include +#include +#include +#include + +using namespace std; + +#include "got.h" +#include "swap.h" +#include "image.h" +#include "symbol.h" +#include "section.h" +#include "postlinker.h" +#include "symboltable.h" +#include "stringtable.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#define Version "2005-4-14" +#define Copyright \ +"Copyright (c) 2004-2005 Greg Parker\n" \ +"Copyright (c) 2001 David E. O'Brien\n" \ +"Copyright (c) 1996-1998 John D. Polstra\n" \ +"All rights reserved.\n" \ +"\n" \ +"Redistribution and use in source and binary forms, with or without\n" \ +"modification, are permitted provided that the following conditions\n" \ +"are met:\n" \ +"1. Redistributions of source code must retain the above copyright\n" \ +" notice, this list of conditions and the following disclaimer.\n" \ +"2. Redistributions in binary form must reproduce the above copyright\n" \ +" notice, this list of conditions and the following disclaimer in the\n" \ +" documentation and/or other materials provided with the distribution.\n" \ +"\n" \ +"THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n" \ +"ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n" \ +"IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"\ +"ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n" \ +"FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"\ +"DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n" \ +"OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n" \ +"HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n"\ +"LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n" \ +"OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n" \ +"SUCH DAMAGE.\n" + +int Verbose = 0; + + +static void version(void) +{ + fprintf(stderr, "peal-postlink version %s\n\n", Version); + fprintf(stderr, "%s\n", Copyright); +} + + +static void usage(const char *name) +{ + fprintf(stderr, + "Usage: %s [-vV] [-K filename] [-t resType] [-s resID] [-o output] filename\n" + " -V: print version info\n" + " -v: verbose\n" + " -K : only keep global symbols listed in file 'filename'\n" + " -t : set resource type for -s (default is 'armc')\n" + " -o : write result to file 'output'\n" + " -s : write result in .ro format with one resource per ELF section\n" + " (default is .bin format with everything in one resource)\n" + , name); + exit(1); +} + +int main(int argc, char **argv) +{ + int fd; + int err; + struct stat sb; + int ch; + const char *infilename; + const char *outfilename = NULL; + const char *keepfilename = NULL; + const char *selfname; + vector *keepSymbols = NULL; + int printversion = 0; + int splitindex = -1; + const char *resType = "armc"; + + // Parse options + Verbose = 0; + selfname = strrchr(argv[0], '/'); + if (!selfname) selfname = argv[0]; + + while ((ch = getopt(argc, argv, "vVK:o:s:t:")) != -1) { + switch (ch) { + case 'V': + printversion = 1; + break; + + case 'v': + Verbose = 1; + break; + + case 'K': + if (keepfilename) { + fprintf(stderr, "%s: -K may be used only once\n", selfname); + usage(selfname); + } else { + keepfilename = optarg; + } + break; + + case 'o': + if (outfilename) { + fprintf(stderr, "%s: -o may be used only once\n", selfname); + usage(selfname); + } else { + outfilename = optarg; + } + break; + + case 's': + if (splitindex != -1) { + fprintf(stderr, "%s: -s may be used only once\n", selfname); + usage(selfname); + } else { + splitindex = atoi(optarg); + } + break; + + case 't': + resType = optarg; + if (strlen(resType) != 4) { + fprintf(stderr, "%s: -t resource type must be exactly four characters long\n", selfname); + usage(selfname); + } + break; + + case '?': + default: + usage(selfname); + break; + } + } + + argc -= optind; + argv += optind; + + if (printversion) { + version(); + } + + if (argc == 0) { + fprintf(stderr, "%s: no file specified\n", selfname); + usage(selfname); + } + + infilename = argv[argc-1]; + if (!outfilename) outfilename = infilename; + + + // Read keepfile, if any + if (keepfilename) { + FILE *keepfile = fopen(keepfilename, "r"); + if (!keepfile) { perror(keepfilename); return 1; } + keepSymbols = new vector(0); + char buf[1024]; + char *keep; + size_t len; + while ((keep = fgets(buf, sizeof(buf), keepfile))) { + char *end = strstr(keep, "\n"); + if (end) len = end - keep; // skip newline, if any + else len = strlen(keep); + keepSymbols->push_back(string(keep, len)); + } + } + + + // Read file into memory + + fd = open(infilename, O_RDONLY | O_BINARY, 0); + if (fd < 0) { perror(infilename); return 1; } + + err = fstat(fd, &sb); + if (err) { perror(infilename); return 1; } + + uint8_t *buf = (uint8_t *)malloc(sb.st_size); + if (sb.st_size != read(fd, buf, sb.st_size)) { + perror(infilename); return 1; + } + close(fd); + + + // Read the ELF image, undo relocations, and record new relocations. + + Image image(buf); + + + // Scrub the symbol table. + // - keep all global symbols + // - keep a symbol for data and text sections + // - fixme apply export list here + + image.symtab().strip(keepSymbols); + image.trimSections(); // removes all string tables + image.addSectionGlobals(); + image.buildSymbolStringTable(); + image.buildRelocations(); + image.buildSectionStringTable(); + + image.write(resType, splitindex, outfilename); + + // fixme paranoia checks: + // all ro+alloc+contents sections contiguous (in file and vm) + // no ro+alloc-contents sections + // all rw+alloc sections coniguous (in file and vm) + + return 0; +} diff --git a/postlink/postlinker.h b/postlink/postlinker.h new file mode 100644 index 0000000..7805406 --- /dev/null +++ b/postlink/postlinker.h @@ -0,0 +1,30 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#ifndef POSTLINKER_H +#define POSTLINKER_H + +extern int Verbose; + +#endif diff --git a/postlink/relocation.cc b/postlink/relocation.cc new file mode 100644 index 0000000..dbe600a --- /dev/null +++ b/postlink/relocation.cc @@ -0,0 +1,67 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#include "elf.h" +#include "swap.h" +#include "symboltable.h" +#include "complain.h" + +#include "relocation.h" + + +Relocation::Relocation(uint8_t newType, uint32_t newOffset, const Symbol *newSymbol, int32_t newAddend) + : mType(newType), + mOffset(newOffset), + mAddend(newAddend), + mSymbol(newSymbol) +{ + // no local-symbol-relative relocations allowed + if (!mSymbol->isGlobal()) + error("attempted relocation relative to non-global symbol '%s'", + mSymbol->name().c_str()); +} + +Relocation::Relocation(const Elf32_Rel *rel, const SymbolTable& symtab, const Section §ion) + : mType(ELF32_R_TYPE(swap32(rel->r_info))), + mOffset(swap32(rel->r_offset)), + mAddend(0), + mSymbol(symtab[ELF32_R_SYM(swap32(rel->r_info))]) +{ + // use offset in section, not vm address + mOffset -= section.vmaddr(); +} + +uint8_t Relocation::type(void) const { return mType; } +uint32_t Relocation::offset(void) const { return mOffset; } +int32_t Relocation::addend(void) const { return mAddend; } +const Symbol *Relocation::symbol(void) const { return mSymbol; } + +Elf32_Rela Relocation::asElf(const SymbolTable& symtab) const +{ + Elf32_Rela result; + result.r_offset = swap32(mOffset); + result.r_info = swap32(ELF32_R_INFO(symtab.indexOf(mSymbol), mType)); + result.r_addend = swap32(mAddend); + return result; +} diff --git a/postlink/relocation.h b/postlink/relocation.h new file mode 100644 index 0000000..e389c88 --- /dev/null +++ b/postlink/relocation.h @@ -0,0 +1,55 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#ifndef RELOCATION_H +#define RELOCATION_H + +#include "elf.h" + +class Symbol; +class SymbolTable; +class Section; + +class Relocation { + // R_ARM_RELATIVE at runtime: + // *(section_base + mOffset) = mSymbol.vmaddr + mAddend + // fixme this might not really be R_ARM_RELATIVE + uint8_t mType; + uint32_t mOffset; // of address to change, in containing section + int32_t mAddend; // offset from symbol + const Symbol *mSymbol; // symbol whose vmaddr should be added + +public: + Relocation(uint8_t newType, uint32_t newOffset, const Symbol *newSymbol, int32_t newAddend); + Relocation(const Elf32_Rel *rel, const SymbolTable& symtab, const Section& section); + + uint8_t type(void) const; + uint32_t offset(void) const; + int32_t addend(void) const; + const Symbol *symbol(void) const; + + Elf32_Rela Relocation::asElf(const SymbolTable& symtab) const; +}; + +#endif diff --git a/postlink/section.cc b/postlink/section.cc new file mode 100644 index 0000000..614f11d --- /dev/null +++ b/postlink/section.cc @@ -0,0 +1,334 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#include +#include +#include + +#include "elf.h" +#include "got.h" +#include "swap.h" +#include "image.h" +#include "symbol.h" +#include "complain.h" +#include "relocation.h" +#include "stringtable.h" + +#include "section.h" + + +Section::Section(Image& newImage) + : mImage(newImage) +{ } + +Section::Section(Image &newImage, string newName, uint32_t newType, uint32_t newFlags, uint32_t newVMAddr, uint8_t *newContents, uint32_t newSize) + : mName(newName), + mType(newType), + mFlags(newFlags), + mVMaddr(newVMAddr), + mAlign(4), + mSize(newSize), + mContents(newContents), + mLink(0), + mInfo(0), + mEntrySize(0), + mImage(newImage), + mBaseSymbol(NULL) +{ } + +void Section::read(Elf32_Shdr *shdr) +{ + if (mImage.strtab()) { + mName = (*mImage.strtab())[swap32(shdr->sh_name)]; + } else { + mName = ".shstrtab"; // this is the section name strtab itself + } + mType = swap32(shdr->sh_type); + mFlags = swap32(shdr->sh_flags); + mVMaddr = swap32(shdr->sh_addr); + mAlign = swap32(shdr->sh_addralign); + mSize = swap32(shdr->sh_size); + mContents = mImage.contents() + swap32(shdr->sh_offset); + // relocations will be read later + mLink = 0; + mInfo = 0; + mEntrySize = swap32(shdr->sh_entsize); + mBaseSymbol = NULL; +} + +void Section::reserveThumbThunk(const Relocation &r) +{ + Thunk query(r.symbol(), r.addend()); + vector::iterator t; + // fixme slow, should use hash_map + t = find(mThumbThunks.begin(), mThumbThunks.end(), query); + if (t == mThumbThunks.end()) mThumbThunks.push_back(query); +} + +void Section::reserveARMThunk(const Relocation &r) +{ + Thunk query(r.symbol(), r.addend()); + vector::iterator t; + // fixme slow, should use hash_map + t = find(mARMThunks.begin(), mARMThunks.end(), query); + if (t == mARMThunks.end()) mARMThunks.push_back(query); +} + +void Section::reserveThunkFromThumb(const Relocation &r, uint16_t insn1, + uint16_t insn2) +{ + uint16_t opcode1 = insn1 >> 11; + uint16_t opcode2 = insn2 >> 11; + if (opcode1 == 0x001e && opcode2 == 0x001f) { + // BL: Thumb->Thumb branch, use Thumb thunk + reserveThumbThunk(r); + } else if (opcode1 == 0x001e && opcode2 == 0x001d) { + // BLX: Thumb->ARM branch, use ARM thunk + reserveARMThunk(r); + } else { + unimplemented("unexpected R_ARM_THM_PC22 relocation for Thumb insns " + "0x%x, 0x%x", insn1, insn2); + } +} + +void Section::reserveThunkFromARM(const Relocation &r, uint32_t insn) +{ + uint32_t cond = (insn & 0xf0000000) >> 28; + uint32_t opcode = (insn & 0x0e000000) >> 25; + if (opcode == 0x05) { + if (cond == 0x0f) { + // BLX: ARM->Thumb branch, use Thumb thunk + reserveThumbThunk(r); + } else { + // Bcc, BLcc: ARM->ARM branch, use ARM thunk + reserveARMThunk(r); + } + } else { + // unknown instruction + unimplemented("unexpected R_ARM_PC24 relocation for ARM insn 0x%x", + insn); + } +} + +void Section::applyRelocations(Elf32_Shdr *rhdr) +{ + Elf32_Rel *rel = (Elf32_Rel *) + (mImage.contents() + swap32(rhdr->sh_offset)); + Elf32_Rel *relEnd = (Elf32_Rel *) + ((uint8_t *)rel + swap32(rhdr->sh_size)); + + for ( ; rel < relEnd; ++rel) { + Relocation r(rel, mImage.symtab(), *this); + const Section *symSection = r.symbol()->section(); + if (!symSection) unimplemented("relocation relative to absolute or common symbol"); + + switch (r.type()) { + case R_ARM_PC24: + // Linker stored the offset from here to a symbol in a branch insn. + // This needs no additional relocation if here and the symbol + // are in the same section. + if (this == symSection) { + // Source and dest are in the same section - nothing to do + } else { + // Source and dest are in different sections, which may slide + // relative to each other - create a relocation and a thunk + int32_t offset = peek32(r.offset()) & 0x00ffffff; // SIGNED!! + // sign-extend and convert to byte offset from start of insn + offset = ((offset << 8) >> 8) * 4 + 8; + Relocation r2 = Relocation(R_ARM_PC24, r.offset(), + symSection->baseSymbol(), + vmaddr() + r.offset() + + offset - symSection->vmaddr()); + mRelocations.push_back(r2); + reserveThunkFromARM(r2, peek32(r.offset())); + } + break; + + case R_ARM_THM_PC22: + // Like R_ARM_PC24, except each of the next two Thumb + // instructions contains half of a 22-bit offset. + if (this == symSection) { + // Source and dest are in the same section - nothing to do + } else { + // Source and dest are in different sections, which may slide + // relative to each other - create a relocation and a thunk + int32_t offset_hi = peek16(r.offset()) & 0x07ff; + int32_t offset_lo = peek16(r.offset()+2) & 0x07ff; + int32_t offset = (offset_hi << 11) | offset_lo; + // sign-extend and convert to byte offset from start of insn + offset = ((offset << 10) >> 10) * 2 + 4; + Relocation r2 = Relocation(R_ARM_THM_PC22, r.offset(), + symSection->baseSymbol(), + vmaddr() + r.offset() + + offset - symSection->vmaddr()); + + mRelocations.push_back(r2); + reserveThunkFromThumb(r2, peek16(r.offset()), + peek16(r.offset()+2)); + } + break; + + case R_ARM_GOTOFF: + // Linker stored the offset from the GOT to a target symbol. + // This needs no additional relocation if the symbol is in r/w mem. + if (!symSection->isReadOnly()) { + // Target symbol is in a r/w section - nothing to do + // At runtime, the GOT and all r/w sections will be + // in the same places relative to each other, so + // linker-generated GOT offsets will be correct. + } else { + // Target symbol is in a r/o section - create relocation + // At runtime, the GOT and the r/o sections will move + // relative to each other. + mRelocations.push_back + (Relocation(R_ARM_GOTOFF, r.offset(), + symSection->baseSymbol(), + peek32(r.offset()) - (symSection->vmaddr() - mImage.got().vmaddr()))); + } + break; + + case R_ARM_GOT32: { + // Linker stored the absolute address of a symbol in the GOT. + // Find the GOT entry containing the symbol, and create a + // relocation that will change the *GOT entry* at runtime. + // These new relocations aren't actually created until + // GOT::buildRelocations() is called. + uint32_t sym_vmaddr = r.symbol()->vmaddr(thumb); + GOT& got = mImage.got(); + unsigned int g; + for (g = 0; g < got.entries().size(); g++) { + if (got.entries()[g] == sym_vmaddr) { + if (got.symbols()[g] == NULL) { + got.symbols()[g] = r.symbol(); + } else if (got.symbols()[g] != r.symbol()) { + error("single GOT entry has multiple R_ARM_GOT32 uses"); + } + break; + } + } + if (g == got.entries().size()) { + error("R_ARM_GOT32 relocation has no associated GOT entry (symbol %s, symbol vmaddr 0x%x, section %s", r.symbol()->name().c_str(), sym_vmaddr, symSection->name().c_str()); + } + break; + } + case R_ARM_ABS32: + // Linker stored an absolute address at r.offset() in this section + // Subtract symbol section's linker-determined vmaddr and relocate + // at runtime using symbol section's base symbol. + mRelocations.push_back + (Relocation(R_ARM_ABS32, r.offset(), symSection->baseSymbol(), + peek32(r.offset()) - symSection->vmaddr())); + break; + + case R_ARM_REL32: + // Linker stored the offset between here and the symbol. + // If here and the symbol are in different sections, they + // may move relative to each other at runtime. + if (this == symSection) { + // Source and dest are in the same section - nothing to do + } else { + // Source and dest are in different sections, which may slide + // relative to each other - create a relocation + mRelocations.push_back + (Relocation(R_ARM_REL32, r.offset(), + symSection->baseSymbol(), + vmaddr() + r.offset() + peek32(r.offset()) - symSection->vmaddr())); + } + break; + + case R_ARM_GOTPC: + // Like R_ARM_REL32, but the symbol is the start of the GOT. + // Replace with an ordinary R_ARM_REL32 relocation that uses + // the GOT's section symbol instead of _GLOBAL_OFFSET_TABLE_. + if (isReadOnly()) { + mRelocations.push_back + (Relocation(R_ARM_REL32, r.offset(), + mImage.got().baseSymbol(), + vmaddr() + r.offset() + peek32(r.offset()) - mImage.got().vmaddr())); + } else { + // read/write sections do not move relative to the GOT. + } + break; + + case R_ARM_PLT32: + warning("ignoring R_ARM_PLT32 relocation (symbol '%s')", + r.symbol()->name().c_str()); + break; + + default: + unimplemented("relocation type %d", r.type()); + break; + } + } +} + +bool Section::isReadOnly(void) const { return ! (mFlags & SHF_WRITE); } +const string& Section::name(void) const { return mName; } +uint32_t Section::vmaddr(void) const { return mVMaddr; } +uint32_t Section::type(void) const { return mType; } + +Symbol *Section::baseSymbol(void) const +{ + if (!mBaseSymbol) { + mBaseSymbol = new Symbol(mName, this, 0, STB_GLOBAL, STT_SECTION); + } + return mBaseSymbol; +} + +void Section::setLink(uint32_t newLink) { mLink = newLink; } +void Section::setInfo(uint32_t newInfo) { mInfo = newInfo; } +void Section::setEntrySize(uint32_t newEntrySize) { mEntrySize = newEntrySize; } + + +void Section::emit(Elf32_Shdr *shdr, uint8_t *&buf, uint32_t& bufLen) +{ + uint32_t offset = bufLen; + + + // add blank space for relocation thunks + mThunkSize = 0; + mThunkSize += mThumbThunks.size() * 16; // Thumb thunks 16 bytes each + mThunkSize += mARMThunks.size() * 8; // ARM thunks 8 bytes each + if (mThunkSize && (mSize % 4)) mThunkSize += 4 - (mSize%4); // thunks are 4-byte aligned + mSize += mThunkSize; + + // write shdr before buf gets reallocated (shdr points into buf) + shdr->sh_name = swap32(mImage.strtab()->indexOf(mName)); + shdr->sh_type = swap32(mType); + shdr->sh_flags = swap32(mFlags); + shdr->sh_addr = swap32(mVMaddr); + shdr->sh_offset = swap32(offset); + shdr->sh_size = swap32(mSize); + shdr->sh_link = swap32(mLink); + shdr->sh_info = swap32(mInfo); + shdr->sh_addralign = swap32(mAlign); + shdr->sh_entsize = swap32(mEntrySize); + + if (mType != SHT_NOBITS) { + bufLen += mSize; + buf = (uint8_t *)realloc(buf, bufLen); + memcpy(buf+offset, mContents, mSize - mThunkSize); + memset(buf+offset+mSize-mThunkSize, 0, mThunkSize); + } +} diff --git a/postlink/section.h b/postlink/section.h new file mode 100644 index 0000000..a1c02d8 --- /dev/null +++ b/postlink/section.h @@ -0,0 +1,129 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#ifndef SECTION_H +#define SECTION_H + +#include +#include +#include + +using namespace std; + +#include "elf.h" +#include "swap.h" +#include "relocation.h" + +class Image; +class Symbol; + +class Thunk { + public: + Thunk(const Symbol *newSymbol, int32_t newAddend) + : symbol(newSymbol), addend(newAddend) { } + bool operator==(const Thunk &other) const { + return (symbol == other.symbol && addend == other.addend); + } + protected: + const Symbol *symbol; + int32_t addend; +}; + +class Section { + protected: + string mName; + uint32_t mType; + uint32_t mFlags; + uint32_t mVMaddr; + uint32_t mAlign; + uint32_t mSize; + uint8_t *mContents; // section's bytes, or NULL (NEEDS SWAP) + + uint32_t mLink; + uint32_t mInfo; + + uint32_t mEntrySize; + + Image& mImage; + vector mRelocations; // to apply to this section + mutable Symbol *mBaseSymbol; // symbol pointing to this section, offset 0 + vector mARMThunks; // thunks for branches out of this section + vector mThumbThunks; // thunks for branches out of this section + size_t mThunkSize; + + void reserveARMThunk(const Relocation &r); + void reserveThumbThunk(const Relocation &r); + void reserveThunkFromARM(const Relocation &r, uint32_t insn); + void reserveThunkFromThumb(const Relocation &r, uint16_t insn1, uint16_t insn2); + +public: + Section(Image& newImage); + Section(Image &newImage, string newName, uint32_t newType, uint32_t newFlags, uint32_t newVMAddr, uint8_t *newContents, uint32_t newSize); + virtual ~Section(void) { } + + virtual void read(Elf32_Shdr *shdr); + + void applyRelocations(Elf32_Shdr *rhdr); + + bool isReadOnly(void) const; + const string& name(void) const; + uint32_t vmaddr(void) const; + uint32_t type(void) const; + uint32_t flags(void) const { return mFlags; } + uint32_t size(void) const { return mSize; } + uint32_t thunkSize(void) const { return mThunkSize; } + uint32_t alignment(void) const { return mAlign; } + + Symbol *baseSymbol(void) const; + vector& relocations(void) { return mRelocations; } + + void setLink(uint32_t newLink); + void setInfo(uint32_t newInfo); + void setEntrySize(uint32_t newEntrySize); + + virtual void emit(Elf32_Shdr *shdr, uint8_t *&buf, uint32_t& bufLen); + + + uint32_t peek32(uint32_t offset) { + uint32_t *src = (uint32_t *)(mContents+offset); + return swap32(*src); + } + + uint16_t peek16(uint32_t offset) { + uint16_t *src = (uint16_t *)(mContents+offset); + return swap16(*src); + } + + uint8_t peek8(uint32_t offset) { + uint8_t *src = (uint8_t *)(mContents+offset); + return *src; + } + + void poke32(uint32_t offset, uint32_t value) { + uint32_t *dst = (uint32_t *)(mContents+offset); + *dst = swap32(value); + } +}; + +#endif diff --git a/postlink/stringtable.h b/postlink/stringtable.h new file mode 100644 index 0000000..a9efc36 --- /dev/null +++ b/postlink/stringtable.h @@ -0,0 +1,91 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#ifndef STRINGTABLE_H +#define STRINGTABLE_H + +#include + +#include +#include + +using namespace std; + +#include "elf.h" +#include "swap.h" +#include "image.h" +#include "section.h" +#include "complain.h" + + +using namespace std; + +class StringTable : public Section { + +public: + StringTable(Image& newImage) + : Section(newImage, string(".strtab"), SHT_STRTAB, 0, 0, (uint8_t *)calloc(1, 1), 1) + { + // strtab containing the empty string, unless read() replaces it + } + + void read(Elf32_Shdr *shdr) + { + Section::read(shdr); + + char *strings = (char *)malloc(mSize); + memcpy(strings, mContents, mSize); + mContents = (uint8_t *)strings; + } + + string operator[](int offset) const + { + return string((char *)mContents+offset); + } + + void addString(const string& str) + { + const char *cstr = str.c_str(); + int len = strlen(cstr) + 1; + mContents = (uint8_t *)realloc((char *)mContents, mSize + len); + memcpy((char *)mContents + mSize, cstr, len); + mSize += len; + } + + int indexOf(const string& str) const + { + const char *cstr = str.c_str(); + const char *strings = (const char *)mContents; + for (const char *s = strings; + s < strings+mSize; + s++) + { + if (0 == strcmp(s, cstr)) return s - strings; + } + error("string %s not in strtab", cstr); + return -1; + } +}; + +#endif diff --git a/postlink/swap.h b/postlink/swap.h new file mode 100644 index 0000000..80d372d --- /dev/null +++ b/postlink/swap.h @@ -0,0 +1,104 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#ifndef SWAP_H +#define SWAP_H + +#include "elf.h" + + +static inline uint32_t swap32_68K(uint32_t v) +{ +#if !defined(__i386__) + return v; +#else + return ( + ((v & 0x000000ff) << 24) | + ((v & 0x0000ff00) << 8) | + ((v & 0x00ff0000) >> 8) | + ((v & 0xff000000) >> 24) + ); +#endif +} + + +static inline uint32_t swap32(uint32_t v) +{ +#if defined(__i386__) + return v; +#else + return ( + ((v & 0x000000ff) << 24) | + ((v & 0x0000ff00) << 8) | + ((v & 0x00ff0000) >> 8) | + ((v & 0xff000000) >> 24) + ); +#endif +} + + +static inline uint16_t swap16_68K(uint16_t v) +{ +#if !defined(__i386__) + return v; +#else + return ( + ((v & 0x00ff) << 8) | + ((v & 0xff00) >> 8) + ); +#endif +} + + +static inline uint16_t swap16(uint16_t v) +{ +#if defined(__i386__) + return v; +#else + return ( + ((v & 0x00ff) << 8) | + ((v & 0xff00) >> 8) + ); +#endif +} + + +static inline void swap_ehdr(Elf32_Ehdr *ehdr) +{ + ehdr->e_type = swap16(ehdr->e_type); + ehdr->e_machine = swap16(ehdr->e_machine); + ehdr->e_version = swap32(ehdr->e_version); + ehdr->e_entry = swap32(ehdr->e_entry); + ehdr->e_phoff = swap32(ehdr->e_phoff); + ehdr->e_shoff = swap32(ehdr->e_shoff); + ehdr->e_flags = swap32(ehdr->e_flags); + ehdr->e_ehsize = swap16(ehdr->e_ehsize); + ehdr->e_phentsize = swap16(ehdr->e_phentsize); + ehdr->e_phnum = swap16(ehdr->e_phnum); + ehdr->e_shentsize = swap16(ehdr->e_shentsize); + ehdr->e_shnum = swap16(ehdr->e_shnum); + ehdr->e_shstrndx = swap16(ehdr->e_shstrndx); +} + +#endif diff --git a/postlink/symbol.cc b/postlink/symbol.cc new file mode 100644 index 0000000..9cca8e6 --- /dev/null +++ b/postlink/symbol.cc @@ -0,0 +1,91 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#include +#include +#include "section.h" + +#include "symbol.h" +#include "stringtable.h" + +Symbol::Symbol(const string &newName, const Section *newSection, uint32_t newOffset, + uint8_t newBind, uint8_t newType) + : mName(newName), mSection(newSection), mOffset(newOffset), + mBind(newBind), mType(newType), mSpecialSection(0) +{ +} + +Symbol::Symbol(Image& image, const StringTable& strtab, Elf32_Sym *sym) +{ + mName = strtab[swap32(sym->st_name)]; + uint16_t shndx = swap16(sym->st_shndx); + mSpecialSection = shndx; + if (shndx == SHN_ABS) { + mSection = NULL; + } else if (shndx == SHN_COMMON) { + unimplemented("unresolved common symbol '%s'", mName.c_str()); + } else { + mSection = image.sections()[swap16(sym->st_shndx)]; + } + mOffset = swap32(sym->st_value) - (mSection ? mSection->vmaddr() : 0); + mBind = ELF32_ST_BIND(sym->st_info); + mType = ELF32_ST_TYPE(sym->st_info); +} + + +const string& Symbol::name(void) const { return mName; } +const Section *Symbol::section(void) const { return mSection; } +bool Symbol::isGlobal(void) const { return mBind == STB_GLOBAL; } +uint32_t Symbol::offset(bool interwork) const +{ + if (interwork && mType == STT_LOPROC) return mOffset+1; + else return mOffset; +} +uint32_t Symbol::vmaddr(bool interwork) const +{ + return offset(interwork) + (mSection ? mSection->vmaddr() : 0); +} + +Elf32_Sym Symbol::asElf(const Image& image) const +{ + Elf32_Sym result; + result.st_name = swap32(image.strtab()->indexOf(mName)); + result.st_value = swap32(offset()); + result.st_size = swap32(0); // fixme? + result.st_info = ELF32_ST_INFO(mBind, mType); // 1 byte, don't swap + result.st_other = 0; + + if (mSection) { + vector
::const_iterator pos = find(image.sections().begin(), image.sections().end(), mSection); + if (pos == image.sections().end()) { + result.st_shndx = 0; + } else { + result.st_shndx = swap16(pos - image.sections().begin()); + } + } else { + result.st_shndx = swap16(mSpecialSection); + } + + return result; +} diff --git a/postlink/symbol.h b/postlink/symbol.h new file mode 100644 index 0000000..d5c9d3b --- /dev/null +++ b/postlink/symbol.h @@ -0,0 +1,66 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#ifndef SYMBOL_H +#define SYMBOL_H + +#include +#include + +using namespace std; + +#include "elf.h" + +class Image; +class Section; +class StringTable; + +// used for vmaddr() and offset() to get Thumb interworkable address +#define thumb true + +class Symbol { + string mName; // of symbol + const Section *mSection; // containing symbol + uint32_t mOffset; // of symbol's data in containing section + uint8_t mBind; + uint8_t mType; + uint16_t mSpecialSection; // if mSection == 0, this is st_shndx + +public: + Symbol(const string &newName, const Section *newSection, + uint32_t newOffset, uint8_t newBind, uint8_t newType); + Symbol(Image& image, const StringTable &strtab, Elf32_Sym *sym); + + const string& name(void) const; + const Section *section(void) const; + uint32_t offset(bool interwork = false) const; + bool isGlobal(void) const; + char type(void) const { return mType; } + + uint32_t vmaddr(bool interwork = false) const; + + Elf32_Sym asElf(const Image& image) const; +}; + +#endif diff --git a/postlink/symboltable.cc b/postlink/symboltable.cc new file mode 100644 index 0000000..1203905 --- /dev/null +++ b/postlink/symboltable.cc @@ -0,0 +1,109 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#include "section.h" +#include "symboltable.h" +#include "stringtable.h" + +SymbolTable::SymbolTable(Image& newImage) + : Section(newImage) +{ + // symbol table with single empty symbol, unless replaced by read(). + mSymbols.push_back(new Symbol(string(""), mImage.sections()[0], 0, 0, 0)); +} + + +void SymbolTable::read(Elf32_Shdr *shdr) +{ + Section::read(shdr); + + vector
& sections = mImage.sections(); + Section *section = sections[swap32(shdr->sh_link)]; + StringTable *strtab = dynamic_cast(section); + Elf32_Sym *sym = (Elf32_Sym *)mContents; + Elf32_Sym *end = (Elf32_Sym *)(mContents + mSize); + + mSymbols.erase(mSymbols.begin(), mSymbols.end()); + for ( ; sym < end; ++sym) { + mSymbols.push_back(new Symbol(mImage, *strtab, sym)); + } +} + + +// strip all local symbols +// strip all globals symbols not mentioned in keep[] (if it exists) +void SymbolTable::strip(vector *keep) +{ + vector newSymbols; + newSymbols.push_back(new Symbol(string(""), mImage.sections()[0], 0, 0, 0)); + vector::iterator iter; + for (iter = mSymbols.begin(); iter != mSymbols.end(); ++iter) + { + Symbol *sym = *iter; + const string &name = sym->name(); + + if (name == "PealArmStub" || name == "_PealArmStub") { + // PealArmStub is special - never strip it + newSymbols.push_back(sym); + } + else if (!sym->isGlobal()) { + // local symbol - strip it + } + else if (keep && + keep->end() == find(keep->begin(), keep->end(), name)) + { + // keep list exists, but doesn't have this symbol - strip it + } + else { + newSymbols.push_back(sym); + } + } + + mSymbols = newSymbols; +} + + +void SymbolTable::addSymbol(Symbol *sym) +{ + mSymbols.push_back(sym); +} + + +void SymbolTable::emit(Elf32_Shdr *shdr, uint8_t *&buf, uint32_t& bufLen) +{ + // construct mContents and mSize + mSize = mSymbols.size() * sizeof(Elf32_Sym); + Elf32_Sym *newContents = (Elf32_Sym *)malloc(mSize); + + for (unsigned int i = 0; i < mSymbols.size(); i++) { + newContents[i] = mSymbols[i]->asElf(mImage); + } + + mContents = (uint8_t *)newContents; + + // set mLink to strtab + mLink = find(mImage.sections().begin(), mImage.sections().end(), mImage.strtab()) - mImage.sections().begin(); + + Section::emit(shdr, buf, bufLen); +} diff --git a/postlink/symboltable.h b/postlink/symboltable.h new file mode 100644 index 0000000..1050712 --- /dev/null +++ b/postlink/symboltable.h @@ -0,0 +1,66 @@ +/********** + * Copyright (c) 2004 Greg Parker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **********/ + +#ifndef SYMBOLTABLE_H +#define SYMBOLTABLE_H + +#include +#include + +using namespace std; + +#include "symbol.h" +#include "section.h" + +class SymbolTable : public Section { + vector mSymbols; + +public: + SymbolTable(Image& newImage); + void read(Elf32_Shdr *shdr); + void strip(vector *keep); + void addSymbol(Symbol *sym); + + vector::reference operator[](int index) { + return mSymbols[index]; + } + + Symbol *get(int index) { + return mSymbols[index]; + } + + vector::const_reference operator[](int index) const { + return mSymbols[index]; + } + + size_t indexOf(const Symbol *sym) const { + return find(mSymbols.begin(), mSymbols.end(), sym) - mSymbols.begin(); + } + + size_t size(void) const { return mSymbols.size(); } + + void emit(Elf32_Shdr *shdr, uint8_t *&buf, uint32_t& bufLen); +}; + +#endif -- 2.45.1