--- /dev/null
+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=<reg>`,
+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 <resID>
+ 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 <filename>
+ 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 <filename>
+ 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 <resType>
+ 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 <gparker-peal@sealiesoftware.com>,
+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.
+
+***
--- /dev/null
+/**********
+ * 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 <stdint.h>
+#include <PceNativeCall.h>
+
+// 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;
+}
--- /dev/null
+/**********
+ * 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 <PceNativeCall.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const void *gEmulStateP;
+extern Call68KFuncType *gCall68KFuncP;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+#include <Standalone.h>
+#include <stdint.h>
+#include <stdlib.h>
+#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);
+}
--- /dev/null
+// Demonstate constant data
+char *ReturnOne(void)
+{
+ return "One";
+}
+
+
+// Demonstate non-constant initialized data
+static char two[] = "Two0";
+char *ReturnTwo(void)
+{
+ two[3]++;
+ return two;
+}
--- /dev/null
+/**********
+ * 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 <PalmOS.h>
+#include <stdint.h>
+#include <stdarg.h>
+#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;
+}
--- /dev/null
+// app name and creator code
+application { "PealExample" "????" }
--- /dev/null
+FORM ID 1000 AT (0 0 160 160)\r
+USABLE\r
+NOSAVEBEHIND\r
+BEGIN\r
+ TITLE "PealExample"\r
+END\r
--- /dev/null
+/*-
+ * 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_ */
--- /dev/null
+/*-
+ * 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 <stdint.h>
+#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_ */
--- /dev/null
+/*-
+ * 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_ */
--- /dev/null
+/**********
+ * 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 <PalmOS.h>
+#include <PalmOSGlue.h>
+#include <PceNativeCall.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#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);
+ }
+}
+
+
--- /dev/null
+/**********
+ * 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 <stdint.h>
+
+/*
+ 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
--- /dev/null
+# 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=
--- /dev/null
+/**********
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+
+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);
+}
+
--- /dev/null
+/**********
+ * 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
--- /dev/null
+/*-
+ * 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_ */
--- /dev/null
+/*-
+ * 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 <stdint.h>
+#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_ */
--- /dev/null
+/*-
+ * 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_ */
--- /dev/null
+/**********
+ * 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 <stdint.h>
+#include <vector>
+
+using namespace std;
+
+#include "swap.h"
+#include "section.h"
+#include "relocation.h"
+#include "symbol.h"
+#include "complain.h"
+
+class GOT : public Section {
+ vector<uint32_t> mEntries;
+ vector<const Symbol *> 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<uint32_t>& entries(void) const { return mEntries; }
+ vector<const Symbol *>& 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
--- /dev/null
+/**********
+ * 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 <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#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<Section *>::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<Section *> 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<Section *> newSections;
+
+ if (mGOT) mGOT->buildRelocations();
+
+ for (unsigned int i = 0; i < mSections.size(); i++) {
+ Section *s = mSections[i];
+ vector<Relocation>& 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);
+ }
+}
+
--- /dev/null
+/**********
+ * 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 <vector>
+
+using namespace std;
+
+class Section;
+class SymbolTable;
+class StringTable;
+class GOT;
+
+class Image {
+ uint8_t *mContents;
+ Elf32_Ehdr mEhdr;
+ vector<Elf32_Shdr *>sectionPointers;
+ vector<Section *> 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<Section *>& sections(void) { return mSections; }
+ const vector<Section *>& 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
--- /dev/null
+/**********
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "elf.h"
+
+#include <map>
+#include <string>
+#include <vector>
+#include <algorithm>
+
+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 <filename>: only keep global symbols listed in file 'filename'\n"
+ " -t <resType>: set resource type for -s (default is 'armc')\n"
+ " -o <output>: write result to file 'output'\n"
+ " -s <resID>: 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<string> *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<string>(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;
+}
--- /dev/null
+/**********
+ * 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
--- /dev/null
+/**********
+ * 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;
+}
--- /dev/null
+/**********
+ * 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
--- /dev/null
+/**********
+ * 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 <string>
+#include <vector>
+#include <stdint.h>
+
+#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<Thunk>::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<Thunk>::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);
+ }
+}
--- /dev/null
+/**********
+ * 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 <string>
+#include <vector>
+#include <stdint.h>
+
+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<Relocation> mRelocations; // to apply to this section
+ mutable Symbol *mBaseSymbol; // symbol pointing to this section, offset 0
+ vector<Thunk> mARMThunks; // thunks for branches out of this section
+ vector<Thunk> 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<Relocation>& 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
--- /dev/null
+/**********
+ * 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 <string.h>
+
+#include <vector>
+#include <string>
+
+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
--- /dev/null
+/**********
+ * 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
--- /dev/null
+/**********
+ * 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 <string>
+#include <stdint.h>
+#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<Section *>::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;
+}
--- /dev/null
+/**********
+ * 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 <string>
+#include <stdint.h>
+
+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
--- /dev/null
+/**********
+ * 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<Section *>& sections = mImage.sections();
+ Section *section = sections[swap32(shdr->sh_link)];
+ StringTable *strtab = dynamic_cast<StringTable *>(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<string> *keep)
+{
+ vector<Symbol *> newSymbols;
+ newSymbols.push_back(new Symbol(string(""), mImage.sections()[0], 0, 0, 0));
+ vector<Symbol *>::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);
+}
--- /dev/null
+/**********
+ * 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 <vector>
+#include <algorithm>
+
+using namespace std;
+
+#include "symbol.h"
+#include "section.h"
+
+class SymbolTable : public Section {
+ vector<Symbol *> mSymbols;
+
+public:
+ SymbolTable(Image& newImage);
+ void read(Elf32_Shdr *shdr);
+ void strip(vector<string> *keep);
+ void addSymbol(Symbol *sym);
+
+ vector<Symbol *>::reference operator[](int index) {
+ return mSymbols[index];
+ }
+
+ Symbol *get(int index) {
+ return mSymbols[index];
+ }
+
+ vector<Symbol *>::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