]> asedeno.scripts.mit.edu Git - peal.git/commitdiff
Greg Parker's Palm Elf Arm Loader (PEAL) master
authorAlejandro R. Sedeño <asedeno@mit.edu>
Sun, 18 Mar 2007 17:57:05 +0000 (17:57 +0000)
committerAlejandro R. Sedeño <asedeno@mit.edu>
Sun, 18 Mar 2007 17:57:05 +0000 (17:57 +0000)
http://www.sealiesoftware.com/peal/

37 files changed:
README.txt [new file with mode: 0644]
arm/pealstub.c [new file with mode: 0644]
arm/pealstub.h [new file with mode: 0644]
example/Makefile [new file with mode: 0644]
example/arm/Makefile [new file with mode: 0644]
example/arm/arm.c [new file with mode: 0644]
example/arm/arm2.c [new file with mode: 0644]
example/m68k.c [new file with mode: 0644]
example/pealexample.def [new file with mode: 0644]
example/pealexample.rcp [new file with mode: 0644]
m68k/elf.h [new file with mode: 0644]
m68k/elf32.h [new file with mode: 0644]
m68k/elf_common.h [new file with mode: 0644]
m68k/peal.c [new file with mode: 0644]
m68k/peal.h [new file with mode: 0644]
postlink/Makefile [new file with mode: 0644]
postlink/complain.cc [new file with mode: 0644]
postlink/complain.h [new file with mode: 0644]
postlink/elf.h [new file with mode: 0644]
postlink/elf32.h [new file with mode: 0644]
postlink/elf_common.h [new file with mode: 0644]
postlink/got.h [new file with mode: 0644]
postlink/image.cc [new file with mode: 0644]
postlink/image.h [new file with mode: 0644]
postlink/peal-postlink [new file with mode: 0755]
postlink/postlinker.cc [new file with mode: 0644]
postlink/postlinker.h [new file with mode: 0644]
postlink/relocation.cc [new file with mode: 0644]
postlink/relocation.h [new file with mode: 0644]
postlink/section.cc [new file with mode: 0644]
postlink/section.h [new file with mode: 0644]
postlink/stringtable.h [new file with mode: 0644]
postlink/swap.h [new file with mode: 0644]
postlink/symbol.cc [new file with mode: 0644]
postlink/symbol.h [new file with mode: 0644]
postlink/symboltable.cc [new file with mode: 0644]
postlink/symboltable.h [new file with mode: 0644]

diff --git a/README.txt b/README.txt
new file mode 100644 (file)
index 0000000..7acb173
--- /dev/null
@@ -0,0 +1,399 @@
+Peal: Palm ELF ARM Loader
+version 2005-4-14
+
+Peal is a simple ELF postlinker and loader for Palm OS. It allows ARM 
+code to use global variables and function pointers without restriction.
+
+http://www.sealiesoftware.com/peal/
+
+
+FEATURES
+
+Features supported by Peal and Peal-loaded ARM code:
+
+* Global variables
+
+* Function pointers
+
+* Automatic handling of code segments larger than 64 KB
+
+* Multiple entry point functions
+
+* Access to global variables from m68k code
+
+* Minimum memory usage - code and read-only data are not copied to 
+  feature memory or the heap
+
+* Thumb and ARM/Thumb interworking
+
+
+LIMITATIONS
+
+* Peal is substantially UNTESTED. It may crash, generate incorrect 
+  ARM global data, or modify random memory locations at runtime.
+
+* Peal has some support for C++ code, but it is even less tested.
+
+* Peal does not provide support for arbitrary ARM-ELF code. Only 
+  code built with Peal's postlinker can be loaded by Peal.
+
+* Peal does not provide support for ELF shared libraries.
+
+* Peal uses the stack space provided by PceNativeCall(), which is 
+  only 4 KB by default. There are ways to increase the ARM stack size, 
+  but Peal does not use any of them.
+
+
+USAGE
+
+A synopsis of Peal usage follows. See the example/ directory for a simple 
+demonstration, and the rest of this README for complete details.
+
+0. Build the peal-postlink program in the postlink/ directory:
+      `cd postlink; make`
+
+1. Write ARM code that uses global data or function pointers. ARM 
+   functions intended to be called by m68k code may take a single 
+   parameter. ARM functions that need to call back into m68k code should 
+   use the variables gEmulStateP and gCall68KFuncP from arm/pealstub.h.
+      unsigned long MyArmFunction(void *arg) { ... }
+
+2. Write m68k code that uses the API in m68k/peal.h to load ARM code 
+   and call ARM functions:
+      PealModule m = PealLoadFromResources('armc', 1000);
+      void *address = PealLookupSymbol(m, "MyArmFunction");
+      unsigned long result = PealCall(m, address, myArg);
+      PealUnload(m);
+
+3. Compile m68k/peal.c along with other m68k code.
+
+4. Add -fPIC when compiling to compile all ARM code as position-independent:
+      `arm-palmos-gcc -fPIC ...`
+   Compile arm/pealstub.c along with other ARM code. 
+
+5. Add --emit-relocs when linking ARM code to preserve relocation information:
+      `arm-palmos-ld --emit-relocs ...` 
+   or `arm-palmos-gcc -Wl,--emit-relocs ...`
+
+6. Run the Peal postlinker to generate ARM code resources:
+      `peal-postlink -s 1000 -t armc -o postlinked-rsrcs.ro linked-binary.bin`
+
+7. Add the resources generated by peal-postlink to your Palm program as usual.
+
+
+LARGE CODE
+
+Palm OS limits resources to somewhat less than 64 KB each. There are 
+two ways to use Peal with code or initialized data larger than 64 KB. 
+
+1. Use ld's `--split-by-file` option to split the code into segments 
+   smaller than 64 KB each. Then use `peal-postlink -s ...` 
+   to place each segment into its own Palm resource. Finally, load 
+   the code with PealLoadFromResources(). 
+
+      `arm-palmos-ld --split-by-file=64000 ...`
+   or `arm-palmos-gcc -Wl,--split-by-file=64000`
+
+   This method is fully automatic with Peal. No manual segmentation 
+   or code reassembly is needed. This method also takes the minimum 
+   amount of memory, because PealLoadFromResources() does not need 
+   to copy the code into feature memory or the heap.
+
+   Cross-segment function calls are somewhat less efficient that 
+   intra-segment calls. For maximum performance, order the files on 
+   the link line so files that call each other are close together.
+   Alternatively, use __attribute__((section(...))) to segment by hand.
+
+   For very large source files or large data segments, `--split-by-file` 
+   may still generate segments larger than 64000 bytes. In this case, 
+   Peal automatically splits the segment across multiple resources, 
+   and reassembles it during PealLoadFromResources(). Note that 
+   peal-postlink will warn you that the large segment will require 
+   more memory at runtime, because the reassembled section is 
+   allocated on the dynamic heap and the reassembly process 
+   itself temporarily uses additional heap memory. 
+
+2. Build the code and data as one big binary, using peal-postlink 
+   without the -s option. Split the binary into multiple code resources. 
+   Then reassemble the code resources into a single block in feature 
+   memory or on the heap. Finally, load the code with PealLoad(). 
+
+   This method consumes twice as much memory, and Peal provides no 
+   special support for this reassembly. 
+
+
+C++ COMPATIBILITY
+
+Peal provides support for C++ static constructors and destructors. 
+By default, the static constructors are run during the first 
+PealCall(), and the static destructors are run during PealUnload(). 
+If the C++ static constructors need to use m68K callbacks, you 
+can set up the callback pointers before the first PealCall().
+
+If you need to force constructors or destructors to run earlier, 
+use PealCxxConstruct() and PealCxxDestruct(). The constructors 
+and destructors are run only once, even if you call these functions 
+multiple times.
+
+Support for other C++ code has received little testing. 
+It may or may not work correctly.
+
+
+THUMB COMPATIBILITY
+
+Peal can be used with Thumb code and interworked ARM/Thumb code. 
+Thumb code is usually substantially smaller than equivalent ARM code, 
+but may run more slowly.
+
+PealCall() may be used with ARM functions or Thumb functions. 
+Note that PealLookupAddress(myModule, "MyThumbFunction") returns 
+&MyThumbFunction + 1. This address may be used as a function pointer 
+in Thumb code or interworking-enabled ARM code. However, this address 
+may not be passed to PceNativeCall(). Use PealCall() instead.
+
+PealArmStub() in pealstub.c may be compiled in ARM mode or in Thumb mode: 
+
+If your code is ARM-only:
+   Compile pealstub.c in ARM mode as usual.
+
+If your code is Thumb-only:
+   Compile pealstub.c with `-mthumb -mcallee-super-interworking`. 
+   The latter option is necessary to allow PceNativeCall() to call 
+   PealArmStub() without crashing.
+
+If your code is mixed ARM and Thumb:
+   Compile pealstub.c with either `-mno-thumb -mthumb-interwork` (ARM mode)
+   or `-mthumb -mcallee-super-interworking` (Thumb mode).
+
+
+COMPATIBLITY WITH OTHER COMPILER OPTIONS
+
+Peal can be used with ARM or Thumb code compiled with `-msingle-pic-base`. 
+PealArmStub() sets up register R10 as the PIC register. This option is 
+recommended because it reduces code size and relocation count.
+
+Peal cannot be used with `-msingle-pic-base -mpic-register=<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.
+
+***
diff --git a/arm/pealstub.c b/arm/pealstub.c
new file mode 100644 (file)
index 0000000..d454716
--- /dev/null
@@ -0,0 +1,85 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#include "pealstub.h"
+#include <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;
+}
diff --git a/arm/pealstub.h b/arm/pealstub.h
new file mode 100644 (file)
index 0000000..bdb680e
--- /dev/null
@@ -0,0 +1,41 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#ifndef PEALSTUB_H
+#define PEALSTUB_H
+
+#include <PceNativeCall.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const void *gEmulStateP;
+extern Call68KFuncType *gCall68KFuncP;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/example/Makefile b/example/Makefile
new file mode 100644 (file)
index 0000000..9660205
--- /dev/null
@@ -0,0 +1,28 @@
+WARNINGS = -W -Wall -Wpointer-arith
+
+OPTIMIZATION = -O0
+
+all: pealexample.prc
+
+pealexample.prc: pealexample.def pealexample.o arm/armc.ro pealexample.ro
+       build-prc -o pealexample.prc pealexample.def pealexample.o pealexample.ro arm/armc.ro 
+
+arm/armc.ro: arm
+       make -C arm
+
+pealexample.ro: pealexample.rcp
+       pilrc -ro pealexample.rcp pealexample.ro
+
+pealexample.o: m68k.o peal.o
+       m68k-palmos-gcc m68k.o peal.o -o pealexample.o -lPalmOSGlue
+
+m68k.o: m68k.c ../m68k/peal.h
+       m68k-palmos-gcc $(OPTIMIZATION) $(WARNINGS) -I../m68k -c m68k.c -o m68k.o
+
+peal.o: ../m68k/peal.c ../m68k/peal.h ../m68k/elf.h ../m68k/elf_common.h ../m68k/elf32.h
+       m68k-palmos-gcc $(OPTIMIZATION) $(WARNINGS) -I../m68k -c ../m68k/peal.c -o peal.o
+
+
+clean:
+       rm -f *~ *.o *.ro pealexample.o pealexample.prc
+       make -C arm clean
\ No newline at end of file
diff --git a/example/arm/Makefile b/example/arm/Makefile
new file mode 100644 (file)
index 0000000..00806f7
--- /dev/null
@@ -0,0 +1,15 @@
+WARNINGS = -W -Wall -Wpointer-arith
+
+OPTIMIZATION = -O0 
+
+all: armc.ro
+
+armc.ro: arm.c arm2.c ../../arm/pealstub.c ../../arm/pealstub.h
+       arm-palmos-gcc -fPIC -Os -march=armv4t -c ../../arm/pealstub.c -o pealstub.o
+
+       arm-palmos-gcc -fPIC -Os -Wl,--split-by-file=60000 -march=armv4t -msingle-pic-base -Wl,--emit-relocs -nostartfiles $(WARNINGS) -I../../arm arm.c arm2.c pealstub.o -o armc03e8.bin
+       ../../postlink/peal-postlink -v -s 1000 -o armc.ro armc03e8.bin
+       ../../postlink/peal-postlink -v -o armc.unsplit armc03e8.bin
+
+clean: 
+       rm -f *.o *~ armc.ro armc03e8.bin
diff --git a/example/arm/arm.c b/example/arm/arm.c
new file mode 100644 (file)
index 0000000..97236b1
--- /dev/null
@@ -0,0 +1,45 @@
+#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);
+}
diff --git a/example/arm/arm2.c b/example/arm/arm2.c
new file mode 100644 (file)
index 0000000..a237586
--- /dev/null
@@ -0,0 +1,14 @@
+// Demonstate constant data
+char *ReturnOne(void)
+{
+    return "One";
+}
+
+
+// Demonstate non-constant initialized data
+static char two[] = "Two0";
+char *ReturnTwo(void)
+{
+    two[3]++;
+    return two;
+}
diff --git a/example/m68k.c b/example/m68k.c
new file mode 100644 (file)
index 0000000..82b3f4f
--- /dev/null
@@ -0,0 +1,158 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#include <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;
+}
diff --git a/example/pealexample.def b/example/pealexample.def
new file mode 100644 (file)
index 0000000..0cefe2d
--- /dev/null
@@ -0,0 +1,2 @@
+// app name and creator code
+application { "PealExample" "????" }
diff --git a/example/pealexample.rcp b/example/pealexample.rcp
new file mode 100644 (file)
index 0000000..204bfcc
--- /dev/null
@@ -0,0 +1,6 @@
+FORM ID 1000 AT (0 0 160 160)\r
+USABLE\r
+NOSAVEBEHIND\r
+BEGIN\r
+    TITLE "PealExample"\r
+END\r
diff --git a/m68k/elf.h b/m68k/elf.h
new file mode 100644 (file)
index 0000000..4a73d8a
--- /dev/null
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 2001 David E. O'Brien
+ * Copyright (c) 1996-1997 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/arm/include/elf.h,v 1.4 2003/09/25 01:10:23 peter Exp $
+ */
+
+#ifndef _MACHINE_ELF_H_
+#define        _MACHINE_ELF_H_ 1
+
+/*
+ * EABI ELF definitions for the StrongARM architecture.
+ * See "ARM ELF", document no. `SWS ESPC 0003 A-08' for details.
+ */
+
+#include "elf32.h"     /* Definitions common to all 32 bit architectures. */
+
+#define        ELF_ARCH        EM_ARM
+
+#define        ELF_MACHINE_OK(x) ((x) == EM_ARM)
+
+/*
+ * Relocation types.
+ */
+
+#define        R_ARM_NONE              0       /* No relocation. */
+#define        R_ARM_PC24              1
+#define        R_ARM_ABS32             2
+#define        R_ARM_REL32             3
+#define        R_ARM_PC13              4
+#define        R_ARM_ABS16             5
+#define        R_ARM_ABS12             6
+#define        R_ARM_THM_ABS5          7
+#define        R_ARM_ABS8              8
+#define        R_ARM_SBREL32           9
+#define        R_ARM_THM_PC22          10
+#define        R_ARM_THM_PC8           11
+#define        R_ARM_AMP_VCALL9        12
+#define        R_ARM_SWI24             13
+#define        R_ARM_THM_SWI8          14
+#define        R_ARM_XPC25             15
+#define        R_ARM_THM_XPC22         16
+#define        R_ARM_COPY              20      /* Copy data from shared object. */
+#define        R_ARM_GLOB_DAT          21      /* Set GOT entry to data address. */
+#define        R_ARM_JUMP_SLOT         22      /* Set GOT entry to code address. */
+#define        R_ARM_RELATIVE          23      /* Add load address of shared object. */
+#define        R_ARM_GOTOFF            24      /* Add GOT-relative symbol address. */
+#define        R_ARM_GOTPC             25      /* Add PC-relative GOT table address. */
+#define        R_ARM_GOT32             26      /* Add PC-relative GOT offset. */
+#define        R_ARM_PLT32             27      /* Add PC-relative PLT offset. */
+#define        R_ARM_GNU_VTENTRY       100
+#define        R_ARM_GNU_VTINHERIT     101
+#define        R_ARM_RSBREL32          250
+#define        R_ARM_THM_RPC22         251
+#define        R_ARM_RREL32            252
+#define        R_ARM_RABS32            253
+#define        R_ARM_RPC24             254
+#define        R_ARM_RBASE             255
+
+#define        R_ARM_COUNT             33      /* Count of defined relocation types. */
+
+
+/* Define "machine" characteristics */
+#define        ELF_TARG_CLASS  ELFCLASS32
+#define        ELF_TARG_DATA   ELFDATA2LSB
+#define        ELF_TARG_MACH   EM_ARM
+#define        ELF_TARG_VER    1
+
+#endif /* !_MACHINE_ELF_H_ */
diff --git a/m68k/elf32.h b/m68k/elf32.h
new file mode 100644 (file)
index 0000000..c74f643
--- /dev/null
@@ -0,0 +1,157 @@
+/*-
+ * Copyright (c) 1996-1998 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/sys/elf32.h,v 1.8 2002/05/30 08:32:18 dfr Exp $
+ */
+
+#ifndef _SYS_ELF32_H_
+#define _SYS_ELF32_H_ 1
+
+#include <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_ */
diff --git a/m68k/elf_common.h b/m68k/elf_common.h
new file mode 100644 (file)
index 0000000..ee3a904
--- /dev/null
@@ -0,0 +1,299 @@
+/*-
+ * Copyright (c) 1998 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/sys/elf_common.h,v 1.14 2003/06/18 16:38:22 kan Exp $
+ */
+
+#ifndef _SYS_ELF_COMMON_H_
+#define _SYS_ELF_COMMON_H_ 1
+
+/*
+ * ELF definitions that are independent of architecture or word size.
+ */
+
+/*
+ * Note header.  The ".note" section contains an array of notes.  Each
+ * begins with this header, aligned to a word boundary.  Immediately
+ * following the note header is n_namesz bytes of name, padded to the
+ * next word boundary.  Then comes n_descsz bytes of descriptor, again
+ * padded to a word boundary.  The values of n_namesz and n_descsz do
+ * not include the padding.
+ */
+
+typedef struct {
+       uint32_t        n_namesz;       /* Length of name. */
+       uint32_t        n_descsz;       /* Length of descriptor. */
+       uint32_t        n_type;         /* Type of this note. */
+} Elf_Note;
+
+/* Indexes into the e_ident array.  Keep synced with 
+   http://www.sco.com/developer/gabi/ch4.eheader.html */
+#define EI_MAG0                0       /* Magic number, byte 0. */
+#define EI_MAG1                1       /* Magic number, byte 1. */
+#define EI_MAG2                2       /* Magic number, byte 2. */
+#define EI_MAG3                3       /* Magic number, byte 3. */
+#define EI_CLASS       4       /* Class of machine. */
+#define EI_DATA                5       /* Data format. */
+#define EI_VERSION     6       /* ELF format version. */
+#define EI_OSABI       7       /* Operating system / ABI identification */
+#define EI_ABIVERSION  8       /* ABI version */
+#define OLD_EI_BRAND   8       /* Start of architecture identification. */
+#define EI_PAD         9       /* Start of padding (per SVR4 ABI). */
+#define EI_NIDENT      16      /* Size of e_ident array. */
+
+/* Values for the magic number bytes. */
+#define ELFMAG0                0x7f
+#define ELFMAG1                'E'
+#define ELFMAG2                'L'
+#define ELFMAG3                'F'
+#define ELFMAG         "\177ELF"       /* magic string */
+#define SELFMAG                4               /* magic string size */
+
+/* Values for e_ident[EI_VERSION] and e_version. */
+#define EV_NONE                0
+#define EV_CURRENT     1
+
+/* Values for e_ident[EI_CLASS]. */
+#define ELFCLASSNONE   0       /* Unknown class. */
+#define ELFCLASS32     1       /* 32-bit architecture. */
+#define ELFCLASS64     2       /* 64-bit architecture. */
+
+/* Values for e_ident[EI_DATA]. */
+#define ELFDATANONE    0       /* Unknown data format. */
+#define ELFDATA2LSB    1       /* 2's complement little-endian. */
+#define ELFDATA2MSB    2       /* 2's complement big-endian. */
+
+/* Values for e_ident[EI_OSABI]. */
+#define ELFOSABI_SYSV          0       /* UNIX System V ABI */
+#define ELFOSABI_NONE          ELFOSABI_SYSV   /* symbol used in old spec */
+#define ELFOSABI_HPUX          1       /* HP-UX operating system */
+#define ELFOSABI_NETBSD                2       /* NetBSD */
+#define ELFOSABI_LINUX         3       /* GNU/Linux */
+#define ELFOSABI_HURD          4       /* GNU/Hurd */
+#define ELFOSABI_86OPEN                5       /* 86Open common IA32 ABI */
+#define ELFOSABI_SOLARIS       6       /* Solaris */
+#define ELFOSABI_MONTEREY      7       /* Monterey */
+#define ELFOSABI_IRIX          8       /* IRIX */
+#define ELFOSABI_FREEBSD       9       /* FreeBSD */
+#define ELFOSABI_TRU64         10      /* TRU64 UNIX */
+#define ELFOSABI_MODESTO       11      /* Novell Modesto */
+#define ELFOSABI_OPENBSD       12      /* OpenBSD */
+#define ELFOSABI_ARM           97      /* ARM */
+#define ELFOSABI_STANDALONE    255     /* Standalone (embedded) application */
+
+/* e_ident */
+#define IS_ELF(ehdr)   ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
+                        (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
+                        (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
+                        (ehdr).e_ident[EI_MAG3] == ELFMAG3)
+
+/* Values for e_type. */
+#define ET_NONE                0       /* Unknown type. */
+#define ET_REL         1       /* Relocatable. */
+#define ET_EXEC                2       /* Executable. */
+#define ET_DYN         3       /* Shared object. */
+#define ET_CORE                4       /* Core file. */
+
+/* Values for e_machine. */
+#define EM_NONE                0       /* Unknown machine. */
+#define EM_M32         1       /* AT&T WE32100. */
+#define EM_SPARC       2       /* Sun SPARC. */
+#define EM_386         3       /* Intel i386. */
+#define EM_68K         4       /* Motorola 68000. */
+#define EM_88K         5       /* Motorola 88000. */
+#define EM_486         6       /* Intel i486. */
+#define EM_860         7       /* Intel i860. */
+#define EM_MIPS                8       /* MIPS R3000 Big-Endian only */
+
+/* Extensions.  This list is not complete. */
+#define EM_S370                9       /* IBM System/370 */
+#define EM_MIPS_RS4_BE 10      /* MIPS R4000 Big-Endian */ /* Depreciated */
+#define EM_PARISC      15      /* HPPA */
+#define EM_SPARC32PLUS 18      /* SPARC v8plus */
+#define EM_PPC         20      /* PowerPC 32-bit */
+#define EM_PPC64       21      /* PowerPC 64-bit */
+#define EM_ARM         40      /* ARM */
+#define EM_SPARCV9     43      /* SPARC v9 64-bit */
+#define EM_IA_64       50      /* Intel IA-46 Processor */
+#define EM_X86_64      62      /* Advanced Micro Devices x86-64 */
+#define EM_ALPHA       0x9026  /* Alpha (written in the absence of an ABI */
+
+/* Special section indexes. */
+#define SHN_UNDEF           0          /* Undefined, missing, irrelevant. */
+#define SHN_LORESERVE  0xff00          /* First of reserved range. */
+#define SHN_LOPROC     0xff00          /* First processor-specific. */
+#define SHN_HIPROC     0xff1f          /* Last processor-specific. */
+#define SHN_ABS                0xfff1          /* Absolute values. */
+#define SHN_COMMON     0xfff2          /* Common data. */
+#define SHN_HIRESERVE  0xffff          /* Last of reserved range. */
+
+/* sh_type */
+#define SHT_NULL       0               /* inactive */
+#define SHT_PROGBITS   1               /* program defined information */
+#define SHT_SYMTAB     2               /* symbol table section */
+#define SHT_STRTAB     3               /* string table section */
+#define SHT_RELA       4               /* relocation section with addends */
+#define SHT_HASH       5               /* symbol hash table section */
+#define SHT_DYNAMIC    6               /* dynamic section */ 
+#define SHT_NOTE       7               /* note section */
+#define SHT_NOBITS     8               /* no space section */
+#define SHT_REL                9               /* relocation section - no addends */
+#define SHT_SHLIB      10              /* reserved - purpose unknown */
+#define SHT_DYNSYM     11              /* dynamic symbol table section */ 
+#define SHT_NUM                12              /* number of section types */
+#define SHT_LOOS       0x60000000      /* First of OS specific semantics */
+#define SHT_HIOS       0x6fffffff      /* Last of OS specific semantics */
+#define SHT_LOPROC     0x70000000      /* reserved range for processor */
+#define SHT_HIPROC     0x7fffffff      /* specific section header types */
+#define SHT_LOUSER     0x80000000      /* reserved range for application */
+#define SHT_HIUSER     0xffffffff      /* specific indexes */
+
+/* Flags for sh_flags. */
+#define SHF_WRITE      0x1             /* Section contains writable data. */
+#define SHF_ALLOC      0x2             /* Section occupies memory. */
+#define SHF_EXECINSTR  0x4             /* Section contains instructions. */
+#define SHF_TLS                0x400           /* Section contains TLS data. */
+#define SHF_MASKPROC   0xf0000000      /* Reserved for processor-specific. */
+
+/* Values for p_type. */
+#define PT_NULL                0       /* Unused entry. */
+#define PT_LOAD                1       /* Loadable segment. */
+#define PT_DYNAMIC     2       /* Dynamic linking information segment. */
+#define PT_INTERP      3       /* Pathname of interpreter. */
+#define PT_NOTE                4       /* Auxiliary information. */
+#define PT_SHLIB       5       /* Reserved (not used). */
+#define PT_PHDR                6       /* Location of program header itself. */
+#define        PT_TLS          7       /* Thread local storage segment */
+
+#define PT_COUNT       8       /* Number of defined p_type values. */
+
+#define        PT_LOOS         0x60000000      /* OS-specific */
+#define        PT_HIOS         0x6fffffff      /* OS-specific */
+#define PT_LOPROC      0x70000000      /* First processor-specific type. */
+#define PT_HIPROC      0x7fffffff      /* Last processor-specific type. */
+
+/* Values for p_flags. */
+#define PF_X           0x1     /* Executable. */
+#define PF_W           0x2     /* Writable. */
+#define PF_R           0x4     /* Readable. */
+
+/* Values for d_tag. */
+#define DT_NULL                0       /* Terminating entry. */
+#define DT_NEEDED      1       /* String table offset of a needed shared
+                                  library. */
+#define DT_PLTRELSZ    2       /* Total size in bytes of PLT relocations. */
+#define DT_PLTGOT      3       /* Processor-dependent address. */
+#define DT_HASH                4       /* Address of symbol hash table. */
+#define DT_STRTAB      5       /* Address of string table. */
+#define DT_SYMTAB      6       /* Address of symbol table. */
+#define DT_RELA                7       /* Address of ElfNN_Rela relocations. */
+#define DT_RELASZ      8       /* Total size of ElfNN_Rela relocations. */
+#define DT_RELAENT     9       /* Size of each ElfNN_Rela relocation entry. */
+#define DT_STRSZ       10      /* Size of string table. */
+#define DT_SYMENT      11      /* Size of each symbol table entry. */
+#define DT_INIT                12      /* Address of initialization function. */
+#define DT_FINI                13      /* Address of finalization function. */
+#define DT_SONAME      14      /* String table offset of shared object
+                                  name. */
+#define DT_RPATH       15      /* String table offset of library path. [sup] */
+#define DT_SYMBOLIC    16      /* Indicates "symbolic" linking. [sup] */
+#define DT_REL         17      /* Address of ElfNN_Rel relocations. */
+#define DT_RELSZ       18      /* Total size of ElfNN_Rel relocations. */
+#define DT_RELENT      19      /* Size of each ElfNN_Rel relocation. */
+#define DT_PLTREL      20      /* Type of relocation used for PLT. */
+#define DT_DEBUG       21      /* Reserved (not used). */
+#define DT_TEXTREL     22      /* Indicates there may be relocations in
+                                  non-writable segments. [sup] */
+#define DT_JMPREL      23      /* Address of PLT relocations. */
+#define        DT_BIND_NOW     24      /* [sup] */
+#define        DT_INIT_ARRAY   25      /* Address of the array of pointers to
+                                  initialization functions */
+#define        DT_FINI_ARRAY   26      /* Address of the array of pointers to
+                                  termination functions */
+#define        DT_INIT_ARRAYSZ 27      /* Size in bytes of the array of
+                                  initialization functions. */
+#define        DT_FINI_ARRAYSZ 28      /* Size in bytes of the array of
+                                  terminationfunctions. */
+#define        DT_RUNPATH      29      /* String table offset of a null-terminated
+                                  library search path string. */
+#define        DT_FLAGS        30      /* Object specific flag values. */
+#define        DT_ENCODING     32      /* Values greater than or equal to DT_ENCODING
+                                  and less than DT_LOOS follow the rules for
+                                  the interpretation of the d_un union
+                                  as follows: even == 'd_ptr', even == 'd_val'
+                                  or none */
+#define        DT_PREINIT_ARRAY 32     /* Address of the array of pointers to
+                                  pre-initialization functions. */
+#define        DT_PREINIT_ARRAYSZ 33   /* Size in bytes of the array of
+                                  pre-initialization functions. */
+
+#define        DT_COUNT        33      /* Number of defined d_tag values. */
+
+#define        DT_LOOS         0x6000000d      /* First OS-specific */
+#define        DT_HIOS         0x6fff0000      /* Last OS-specific */
+#define        DT_LOPROC       0x70000000      /* First processor-specific type. */
+#define        DT_HIPROC       0x7fffffff      /* Last processor-specific type. */
+
+/* Values for DT_FLAGS */
+#define        DF_ORIGIN       0x0001  /* Indicates that the object being loaded may
+                                  make reference to the $ORIGIN substitution
+                                  string */
+#define        DF_SYMBOLIC     0x0002  /* Indicates "symbolic" linking. */
+#define        DF_TEXTREL      0x0004  /* Indicates there may be relocations in
+                                  non-writable segments. */
+#define        DF_BIND_NOW     0x0008  /* Indicates that the dynamic linker should
+                                  process all relocations for the object
+                                  containing this entry before transferring
+                                  control to the program. */
+#define        DF_STATIC_TLS   0x0010  /* Indicates that the shared object or
+                                  executable contains code using a static
+                                  thread-local storage scheme. */
+
+/* Values for n_type.  Used in core files. */
+#define NT_PRSTATUS    1       /* Process status. */
+#define NT_FPREGSET    2       /* Floating point registers. */
+#define NT_PRPSINFO    3       /* Process state info. */
+
+/* Symbol Binding - ELFNN_ST_BIND - st_info */
+#define STB_LOCAL      0       /* Local symbol */
+#define STB_GLOBAL     1       /* Global symbol */
+#define STB_WEAK       2       /* like global - lower precedence */
+#define STB_LOPROC     13      /* reserved range for processor */
+#define STB_HIPROC     15      /*  specific symbol bindings */
+
+/* Symbol type - ELFNN_ST_TYPE - st_info */
+#define STT_NOTYPE     0       /* Unspecified type. */
+#define STT_OBJECT     1       /* Data object. */
+#define STT_FUNC       2       /* Function. */
+#define STT_SECTION    3       /* Section. */
+#define STT_FILE       4       /* Source file. */
+#define STT_TLS                6       /* TLS object. */
+#define STT_LOPROC     13      /* reserved range for processor */
+#define STT_HIPROC     15      /*  specific symbol types */
+
+/* Special symbol table indexes. */
+#define STN_UNDEF      0       /* Undefined symbol index. */
+
+#endif /* !_SYS_ELF_COMMON_H_ */
diff --git a/m68k/peal.c b/m68k/peal.c
new file mode 100644 (file)
index 0000000..bf7fcff
--- /dev/null
@@ -0,0 +1,905 @@
+/**********
+ * Copyright (c) 2004-2005 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#include <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);
+    }
+}
+
+
diff --git a/m68k/peal.h b/m68k/peal.h
new file mode 100644 (file)
index 0000000..accb0d1
--- /dev/null
@@ -0,0 +1,109 @@
+/**********
+ * Copyright (c) 2004-2005 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#ifndef PEAL_H
+#define PEAL_H
+
+#include <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
diff --git a/postlink/Makefile b/postlink/Makefile
new file mode 100644 (file)
index 0000000..dbe260b
--- /dev/null
@@ -0,0 +1,22 @@
+# Peal postlinker makefile
+
+RM = rm -f
+
+OPTIMIZATION = -g -O0
+WARNINGS = -W -Wall -Wmissing-prototypes -Wpointer-arith
+
+POSTLINK_SRCS = image.cc postlinker.cc relocation.cc section.cc symbol.cc symboltable.cc complain.cc
+POSTLINK_HDRS = $(POSTLINK_SRCS:.cc=.h) got.h stringtable.h elf.h elf32.h elf_common.h swap.h 
+
+INCDIRS = -I.
+
+all: peal-postlink
+
+peal-postlink: Makefile $(POSTLINK_HDRS) $(POSTLINK_SRCS)
+       $(CXX) $(OPTIMIZATION) $(WARNINGS) $(POSTLINK_SRCS) -o peal-postlink
+
+clean: 
+       $(RM) *~ *.o peal-postlink
+
+.PHONY=all clean
+.SUFFIXES=
diff --git a/postlink/complain.cc b/postlink/complain.cc
new file mode 100644 (file)
index 0000000..81c13ca
--- /dev/null
@@ -0,0 +1,78 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#include "complain.h"
+#include "postlinker.h"
+
+#include <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);
+}
+
diff --git a/postlink/complain.h b/postlink/complain.h
new file mode 100644 (file)
index 0000000..f465b28
--- /dev/null
@@ -0,0 +1,33 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#ifndef COMPLAIN_H
+#define COMPLAIN_H
+
+void inform(char *format, ...);
+void warning(char *format, ...);
+void error(char *format, ...);
+void unimplemented(char *format, ...);
+
+#endif
diff --git a/postlink/elf.h b/postlink/elf.h
new file mode 100644 (file)
index 0000000..4a73d8a
--- /dev/null
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 2001 David E. O'Brien
+ * Copyright (c) 1996-1997 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/arm/include/elf.h,v 1.4 2003/09/25 01:10:23 peter Exp $
+ */
+
+#ifndef _MACHINE_ELF_H_
+#define        _MACHINE_ELF_H_ 1
+
+/*
+ * EABI ELF definitions for the StrongARM architecture.
+ * See "ARM ELF", document no. `SWS ESPC 0003 A-08' for details.
+ */
+
+#include "elf32.h"     /* Definitions common to all 32 bit architectures. */
+
+#define        ELF_ARCH        EM_ARM
+
+#define        ELF_MACHINE_OK(x) ((x) == EM_ARM)
+
+/*
+ * Relocation types.
+ */
+
+#define        R_ARM_NONE              0       /* No relocation. */
+#define        R_ARM_PC24              1
+#define        R_ARM_ABS32             2
+#define        R_ARM_REL32             3
+#define        R_ARM_PC13              4
+#define        R_ARM_ABS16             5
+#define        R_ARM_ABS12             6
+#define        R_ARM_THM_ABS5          7
+#define        R_ARM_ABS8              8
+#define        R_ARM_SBREL32           9
+#define        R_ARM_THM_PC22          10
+#define        R_ARM_THM_PC8           11
+#define        R_ARM_AMP_VCALL9        12
+#define        R_ARM_SWI24             13
+#define        R_ARM_THM_SWI8          14
+#define        R_ARM_XPC25             15
+#define        R_ARM_THM_XPC22         16
+#define        R_ARM_COPY              20      /* Copy data from shared object. */
+#define        R_ARM_GLOB_DAT          21      /* Set GOT entry to data address. */
+#define        R_ARM_JUMP_SLOT         22      /* Set GOT entry to code address. */
+#define        R_ARM_RELATIVE          23      /* Add load address of shared object. */
+#define        R_ARM_GOTOFF            24      /* Add GOT-relative symbol address. */
+#define        R_ARM_GOTPC             25      /* Add PC-relative GOT table address. */
+#define        R_ARM_GOT32             26      /* Add PC-relative GOT offset. */
+#define        R_ARM_PLT32             27      /* Add PC-relative PLT offset. */
+#define        R_ARM_GNU_VTENTRY       100
+#define        R_ARM_GNU_VTINHERIT     101
+#define        R_ARM_RSBREL32          250
+#define        R_ARM_THM_RPC22         251
+#define        R_ARM_RREL32            252
+#define        R_ARM_RABS32            253
+#define        R_ARM_RPC24             254
+#define        R_ARM_RBASE             255
+
+#define        R_ARM_COUNT             33      /* Count of defined relocation types. */
+
+
+/* Define "machine" characteristics */
+#define        ELF_TARG_CLASS  ELFCLASS32
+#define        ELF_TARG_DATA   ELFDATA2LSB
+#define        ELF_TARG_MACH   EM_ARM
+#define        ELF_TARG_VER    1
+
+#endif /* !_MACHINE_ELF_H_ */
diff --git a/postlink/elf32.h b/postlink/elf32.h
new file mode 100644 (file)
index 0000000..c74f643
--- /dev/null
@@ -0,0 +1,157 @@
+/*-
+ * Copyright (c) 1996-1998 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/sys/elf32.h,v 1.8 2002/05/30 08:32:18 dfr Exp $
+ */
+
+#ifndef _SYS_ELF32_H_
+#define _SYS_ELF32_H_ 1
+
+#include <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_ */
diff --git a/postlink/elf_common.h b/postlink/elf_common.h
new file mode 100644 (file)
index 0000000..ee3a904
--- /dev/null
@@ -0,0 +1,299 @@
+/*-
+ * Copyright (c) 1998 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/sys/elf_common.h,v 1.14 2003/06/18 16:38:22 kan Exp $
+ */
+
+#ifndef _SYS_ELF_COMMON_H_
+#define _SYS_ELF_COMMON_H_ 1
+
+/*
+ * ELF definitions that are independent of architecture or word size.
+ */
+
+/*
+ * Note header.  The ".note" section contains an array of notes.  Each
+ * begins with this header, aligned to a word boundary.  Immediately
+ * following the note header is n_namesz bytes of name, padded to the
+ * next word boundary.  Then comes n_descsz bytes of descriptor, again
+ * padded to a word boundary.  The values of n_namesz and n_descsz do
+ * not include the padding.
+ */
+
+typedef struct {
+       uint32_t        n_namesz;       /* Length of name. */
+       uint32_t        n_descsz;       /* Length of descriptor. */
+       uint32_t        n_type;         /* Type of this note. */
+} Elf_Note;
+
+/* Indexes into the e_ident array.  Keep synced with 
+   http://www.sco.com/developer/gabi/ch4.eheader.html */
+#define EI_MAG0                0       /* Magic number, byte 0. */
+#define EI_MAG1                1       /* Magic number, byte 1. */
+#define EI_MAG2                2       /* Magic number, byte 2. */
+#define EI_MAG3                3       /* Magic number, byte 3. */
+#define EI_CLASS       4       /* Class of machine. */
+#define EI_DATA                5       /* Data format. */
+#define EI_VERSION     6       /* ELF format version. */
+#define EI_OSABI       7       /* Operating system / ABI identification */
+#define EI_ABIVERSION  8       /* ABI version */
+#define OLD_EI_BRAND   8       /* Start of architecture identification. */
+#define EI_PAD         9       /* Start of padding (per SVR4 ABI). */
+#define EI_NIDENT      16      /* Size of e_ident array. */
+
+/* Values for the magic number bytes. */
+#define ELFMAG0                0x7f
+#define ELFMAG1                'E'
+#define ELFMAG2                'L'
+#define ELFMAG3                'F'
+#define ELFMAG         "\177ELF"       /* magic string */
+#define SELFMAG                4               /* magic string size */
+
+/* Values for e_ident[EI_VERSION] and e_version. */
+#define EV_NONE                0
+#define EV_CURRENT     1
+
+/* Values for e_ident[EI_CLASS]. */
+#define ELFCLASSNONE   0       /* Unknown class. */
+#define ELFCLASS32     1       /* 32-bit architecture. */
+#define ELFCLASS64     2       /* 64-bit architecture. */
+
+/* Values for e_ident[EI_DATA]. */
+#define ELFDATANONE    0       /* Unknown data format. */
+#define ELFDATA2LSB    1       /* 2's complement little-endian. */
+#define ELFDATA2MSB    2       /* 2's complement big-endian. */
+
+/* Values for e_ident[EI_OSABI]. */
+#define ELFOSABI_SYSV          0       /* UNIX System V ABI */
+#define ELFOSABI_NONE          ELFOSABI_SYSV   /* symbol used in old spec */
+#define ELFOSABI_HPUX          1       /* HP-UX operating system */
+#define ELFOSABI_NETBSD                2       /* NetBSD */
+#define ELFOSABI_LINUX         3       /* GNU/Linux */
+#define ELFOSABI_HURD          4       /* GNU/Hurd */
+#define ELFOSABI_86OPEN                5       /* 86Open common IA32 ABI */
+#define ELFOSABI_SOLARIS       6       /* Solaris */
+#define ELFOSABI_MONTEREY      7       /* Monterey */
+#define ELFOSABI_IRIX          8       /* IRIX */
+#define ELFOSABI_FREEBSD       9       /* FreeBSD */
+#define ELFOSABI_TRU64         10      /* TRU64 UNIX */
+#define ELFOSABI_MODESTO       11      /* Novell Modesto */
+#define ELFOSABI_OPENBSD       12      /* OpenBSD */
+#define ELFOSABI_ARM           97      /* ARM */
+#define ELFOSABI_STANDALONE    255     /* Standalone (embedded) application */
+
+/* e_ident */
+#define IS_ELF(ehdr)   ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
+                        (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
+                        (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
+                        (ehdr).e_ident[EI_MAG3] == ELFMAG3)
+
+/* Values for e_type. */
+#define ET_NONE                0       /* Unknown type. */
+#define ET_REL         1       /* Relocatable. */
+#define ET_EXEC                2       /* Executable. */
+#define ET_DYN         3       /* Shared object. */
+#define ET_CORE                4       /* Core file. */
+
+/* Values for e_machine. */
+#define EM_NONE                0       /* Unknown machine. */
+#define EM_M32         1       /* AT&T WE32100. */
+#define EM_SPARC       2       /* Sun SPARC. */
+#define EM_386         3       /* Intel i386. */
+#define EM_68K         4       /* Motorola 68000. */
+#define EM_88K         5       /* Motorola 88000. */
+#define EM_486         6       /* Intel i486. */
+#define EM_860         7       /* Intel i860. */
+#define EM_MIPS                8       /* MIPS R3000 Big-Endian only */
+
+/* Extensions.  This list is not complete. */
+#define EM_S370                9       /* IBM System/370 */
+#define EM_MIPS_RS4_BE 10      /* MIPS R4000 Big-Endian */ /* Depreciated */
+#define EM_PARISC      15      /* HPPA */
+#define EM_SPARC32PLUS 18      /* SPARC v8plus */
+#define EM_PPC         20      /* PowerPC 32-bit */
+#define EM_PPC64       21      /* PowerPC 64-bit */
+#define EM_ARM         40      /* ARM */
+#define EM_SPARCV9     43      /* SPARC v9 64-bit */
+#define EM_IA_64       50      /* Intel IA-46 Processor */
+#define EM_X86_64      62      /* Advanced Micro Devices x86-64 */
+#define EM_ALPHA       0x9026  /* Alpha (written in the absence of an ABI */
+
+/* Special section indexes. */
+#define SHN_UNDEF           0          /* Undefined, missing, irrelevant. */
+#define SHN_LORESERVE  0xff00          /* First of reserved range. */
+#define SHN_LOPROC     0xff00          /* First processor-specific. */
+#define SHN_HIPROC     0xff1f          /* Last processor-specific. */
+#define SHN_ABS                0xfff1          /* Absolute values. */
+#define SHN_COMMON     0xfff2          /* Common data. */
+#define SHN_HIRESERVE  0xffff          /* Last of reserved range. */
+
+/* sh_type */
+#define SHT_NULL       0               /* inactive */
+#define SHT_PROGBITS   1               /* program defined information */
+#define SHT_SYMTAB     2               /* symbol table section */
+#define SHT_STRTAB     3               /* string table section */
+#define SHT_RELA       4               /* relocation section with addends */
+#define SHT_HASH       5               /* symbol hash table section */
+#define SHT_DYNAMIC    6               /* dynamic section */ 
+#define SHT_NOTE       7               /* note section */
+#define SHT_NOBITS     8               /* no space section */
+#define SHT_REL                9               /* relocation section - no addends */
+#define SHT_SHLIB      10              /* reserved - purpose unknown */
+#define SHT_DYNSYM     11              /* dynamic symbol table section */ 
+#define SHT_NUM                12              /* number of section types */
+#define SHT_LOOS       0x60000000      /* First of OS specific semantics */
+#define SHT_HIOS       0x6fffffff      /* Last of OS specific semantics */
+#define SHT_LOPROC     0x70000000      /* reserved range for processor */
+#define SHT_HIPROC     0x7fffffff      /* specific section header types */
+#define SHT_LOUSER     0x80000000      /* reserved range for application */
+#define SHT_HIUSER     0xffffffff      /* specific indexes */
+
+/* Flags for sh_flags. */
+#define SHF_WRITE      0x1             /* Section contains writable data. */
+#define SHF_ALLOC      0x2             /* Section occupies memory. */
+#define SHF_EXECINSTR  0x4             /* Section contains instructions. */
+#define SHF_TLS                0x400           /* Section contains TLS data. */
+#define SHF_MASKPROC   0xf0000000      /* Reserved for processor-specific. */
+
+/* Values for p_type. */
+#define PT_NULL                0       /* Unused entry. */
+#define PT_LOAD                1       /* Loadable segment. */
+#define PT_DYNAMIC     2       /* Dynamic linking information segment. */
+#define PT_INTERP      3       /* Pathname of interpreter. */
+#define PT_NOTE                4       /* Auxiliary information. */
+#define PT_SHLIB       5       /* Reserved (not used). */
+#define PT_PHDR                6       /* Location of program header itself. */
+#define        PT_TLS          7       /* Thread local storage segment */
+
+#define PT_COUNT       8       /* Number of defined p_type values. */
+
+#define        PT_LOOS         0x60000000      /* OS-specific */
+#define        PT_HIOS         0x6fffffff      /* OS-specific */
+#define PT_LOPROC      0x70000000      /* First processor-specific type. */
+#define PT_HIPROC      0x7fffffff      /* Last processor-specific type. */
+
+/* Values for p_flags. */
+#define PF_X           0x1     /* Executable. */
+#define PF_W           0x2     /* Writable. */
+#define PF_R           0x4     /* Readable. */
+
+/* Values for d_tag. */
+#define DT_NULL                0       /* Terminating entry. */
+#define DT_NEEDED      1       /* String table offset of a needed shared
+                                  library. */
+#define DT_PLTRELSZ    2       /* Total size in bytes of PLT relocations. */
+#define DT_PLTGOT      3       /* Processor-dependent address. */
+#define DT_HASH                4       /* Address of symbol hash table. */
+#define DT_STRTAB      5       /* Address of string table. */
+#define DT_SYMTAB      6       /* Address of symbol table. */
+#define DT_RELA                7       /* Address of ElfNN_Rela relocations. */
+#define DT_RELASZ      8       /* Total size of ElfNN_Rela relocations. */
+#define DT_RELAENT     9       /* Size of each ElfNN_Rela relocation entry. */
+#define DT_STRSZ       10      /* Size of string table. */
+#define DT_SYMENT      11      /* Size of each symbol table entry. */
+#define DT_INIT                12      /* Address of initialization function. */
+#define DT_FINI                13      /* Address of finalization function. */
+#define DT_SONAME      14      /* String table offset of shared object
+                                  name. */
+#define DT_RPATH       15      /* String table offset of library path. [sup] */
+#define DT_SYMBOLIC    16      /* Indicates "symbolic" linking. [sup] */
+#define DT_REL         17      /* Address of ElfNN_Rel relocations. */
+#define DT_RELSZ       18      /* Total size of ElfNN_Rel relocations. */
+#define DT_RELENT      19      /* Size of each ElfNN_Rel relocation. */
+#define DT_PLTREL      20      /* Type of relocation used for PLT. */
+#define DT_DEBUG       21      /* Reserved (not used). */
+#define DT_TEXTREL     22      /* Indicates there may be relocations in
+                                  non-writable segments. [sup] */
+#define DT_JMPREL      23      /* Address of PLT relocations. */
+#define        DT_BIND_NOW     24      /* [sup] */
+#define        DT_INIT_ARRAY   25      /* Address of the array of pointers to
+                                  initialization functions */
+#define        DT_FINI_ARRAY   26      /* Address of the array of pointers to
+                                  termination functions */
+#define        DT_INIT_ARRAYSZ 27      /* Size in bytes of the array of
+                                  initialization functions. */
+#define        DT_FINI_ARRAYSZ 28      /* Size in bytes of the array of
+                                  terminationfunctions. */
+#define        DT_RUNPATH      29      /* String table offset of a null-terminated
+                                  library search path string. */
+#define        DT_FLAGS        30      /* Object specific flag values. */
+#define        DT_ENCODING     32      /* Values greater than or equal to DT_ENCODING
+                                  and less than DT_LOOS follow the rules for
+                                  the interpretation of the d_un union
+                                  as follows: even == 'd_ptr', even == 'd_val'
+                                  or none */
+#define        DT_PREINIT_ARRAY 32     /* Address of the array of pointers to
+                                  pre-initialization functions. */
+#define        DT_PREINIT_ARRAYSZ 33   /* Size in bytes of the array of
+                                  pre-initialization functions. */
+
+#define        DT_COUNT        33      /* Number of defined d_tag values. */
+
+#define        DT_LOOS         0x6000000d      /* First OS-specific */
+#define        DT_HIOS         0x6fff0000      /* Last OS-specific */
+#define        DT_LOPROC       0x70000000      /* First processor-specific type. */
+#define        DT_HIPROC       0x7fffffff      /* Last processor-specific type. */
+
+/* Values for DT_FLAGS */
+#define        DF_ORIGIN       0x0001  /* Indicates that the object being loaded may
+                                  make reference to the $ORIGIN substitution
+                                  string */
+#define        DF_SYMBOLIC     0x0002  /* Indicates "symbolic" linking. */
+#define        DF_TEXTREL      0x0004  /* Indicates there may be relocations in
+                                  non-writable segments. */
+#define        DF_BIND_NOW     0x0008  /* Indicates that the dynamic linker should
+                                  process all relocations for the object
+                                  containing this entry before transferring
+                                  control to the program. */
+#define        DF_STATIC_TLS   0x0010  /* Indicates that the shared object or
+                                  executable contains code using a static
+                                  thread-local storage scheme. */
+
+/* Values for n_type.  Used in core files. */
+#define NT_PRSTATUS    1       /* Process status. */
+#define NT_FPREGSET    2       /* Floating point registers. */
+#define NT_PRPSINFO    3       /* Process state info. */
+
+/* Symbol Binding - ELFNN_ST_BIND - st_info */
+#define STB_LOCAL      0       /* Local symbol */
+#define STB_GLOBAL     1       /* Global symbol */
+#define STB_WEAK       2       /* like global - lower precedence */
+#define STB_LOPROC     13      /* reserved range for processor */
+#define STB_HIPROC     15      /*  specific symbol bindings */
+
+/* Symbol type - ELFNN_ST_TYPE - st_info */
+#define STT_NOTYPE     0       /* Unspecified type. */
+#define STT_OBJECT     1       /* Data object. */
+#define STT_FUNC       2       /* Function. */
+#define STT_SECTION    3       /* Section. */
+#define STT_FILE       4       /* Source file. */
+#define STT_TLS                6       /* TLS object. */
+#define STT_LOPROC     13      /* reserved range for processor */
+#define STT_HIPROC     15      /*  specific symbol types */
+
+/* Special symbol table indexes. */
+#define STN_UNDEF      0       /* Undefined symbol index. */
+
+#endif /* !_SYS_ELF_COMMON_H_ */
diff --git a/postlink/got.h b/postlink/got.h
new file mode 100644 (file)
index 0000000..e486387
--- /dev/null
@@ -0,0 +1,93 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#ifndef GOT_H
+#define GOT_H
+
+#include <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
diff --git a/postlink/image.cc b/postlink/image.cc
new file mode 100644 (file)
index 0000000..711fe0d
--- /dev/null
@@ -0,0 +1,478 @@
+/**********
+ * Copyright (c) 2004-2005 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#include <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);
+    }
+}
+
diff --git a/postlink/image.h b/postlink/image.h
new file mode 100644 (file)
index 0000000..1ec4e62
--- /dev/null
@@ -0,0 +1,67 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#ifndef IMAGE_H
+#define IMAGE_H
+
+#include <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
diff --git a/postlink/peal-postlink b/postlink/peal-postlink
new file mode 100755 (executable)
index 0000000..ef1d98a
Binary files /dev/null and b/postlink/peal-postlink differ
diff --git a/postlink/postlinker.cc b/postlink/postlinker.cc
new file mode 100644 (file)
index 0000000..643f97f
--- /dev/null
@@ -0,0 +1,256 @@
+/**********
+ * 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;
+}
diff --git a/postlink/postlinker.h b/postlink/postlinker.h
new file mode 100644 (file)
index 0000000..7805406
--- /dev/null
@@ -0,0 +1,30 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#ifndef POSTLINKER_H
+#define POSTLINKER_H
+
+extern int Verbose;
+
+#endif
diff --git a/postlink/relocation.cc b/postlink/relocation.cc
new file mode 100644 (file)
index 0000000..dbe600a
--- /dev/null
@@ -0,0 +1,67 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#include "elf.h"
+#include "swap.h"
+#include "symboltable.h"
+#include "complain.h"
+
+#include "relocation.h"
+
+
+Relocation::Relocation(uint8_t newType, uint32_t newOffset, const Symbol *newSymbol, int32_t newAddend) 
+    : mType(newType), 
+      mOffset(newOffset), 
+      mAddend(newAddend), 
+      mSymbol(newSymbol) 
+{ 
+    // no local-symbol-relative relocations allowed
+    if (!mSymbol->isGlobal()) 
+        error("attempted relocation relative to non-global symbol '%s'", 
+              mSymbol->name().c_str());
+}
+
+Relocation::Relocation(const Elf32_Rel *rel, const SymbolTable& symtab, const Section &section)
+    : mType(ELF32_R_TYPE(swap32(rel->r_info))), 
+      mOffset(swap32(rel->r_offset)), 
+      mAddend(0), 
+      mSymbol(symtab[ELF32_R_SYM(swap32(rel->r_info))])
+{ 
+    // use offset in section, not vm address
+    mOffset -= section.vmaddr();
+}
+
+uint8_t Relocation::type(void) const { return mType; }
+uint32_t Relocation::offset(void) const { return mOffset; }
+int32_t Relocation::addend(void) const { return mAddend; }
+const Symbol *Relocation::symbol(void) const { return mSymbol; }
+
+Elf32_Rela Relocation::asElf(const SymbolTable& symtab) const 
+{
+    Elf32_Rela result;
+    result.r_offset = swap32(mOffset);
+    result.r_info = swap32(ELF32_R_INFO(symtab.indexOf(mSymbol), mType));
+    result.r_addend = swap32(mAddend);
+    return result;
+}
diff --git a/postlink/relocation.h b/postlink/relocation.h
new file mode 100644 (file)
index 0000000..e389c88
--- /dev/null
@@ -0,0 +1,55 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#ifndef RELOCATION_H
+#define RELOCATION_H
+
+#include "elf.h"
+
+class Symbol;
+class SymbolTable;
+class Section;
+
+class Relocation {
+    // R_ARM_RELATIVE at runtime: 
+    // *(section_base + mOffset) = mSymbol.vmaddr + mAddend
+    // fixme this might not really be R_ARM_RELATIVE
+    uint8_t mType;
+    uint32_t mOffset;       // of address to change, in containing section
+    int32_t mAddend;        // offset from symbol
+    const Symbol *mSymbol;  // symbol whose vmaddr should be added
+
+public:
+    Relocation(uint8_t newType, uint32_t newOffset, const Symbol *newSymbol, int32_t newAddend);
+    Relocation(const Elf32_Rel *rel, const SymbolTable& symtab, const Section& section);
+
+    uint8_t type(void) const;
+    uint32_t offset(void) const;
+    int32_t addend(void) const;
+    const Symbol *symbol(void) const;
+
+    Elf32_Rela Relocation::asElf(const SymbolTable& symtab) const;
+};
+
+#endif
diff --git a/postlink/section.cc b/postlink/section.cc
new file mode 100644 (file)
index 0000000..614f11d
--- /dev/null
@@ -0,0 +1,334 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#include <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);
+    }
+}
diff --git a/postlink/section.h b/postlink/section.h
new file mode 100644 (file)
index 0000000..a1c02d8
--- /dev/null
@@ -0,0 +1,129 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#ifndef SECTION_H
+#define SECTION_H
+
+#include <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
diff --git a/postlink/stringtable.h b/postlink/stringtable.h
new file mode 100644 (file)
index 0000000..a9efc36
--- /dev/null
@@ -0,0 +1,91 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#ifndef STRINGTABLE_H
+#define STRINGTABLE_H
+
+#include <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
diff --git a/postlink/swap.h b/postlink/swap.h
new file mode 100644 (file)
index 0000000..80d372d
--- /dev/null
@@ -0,0 +1,104 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#ifndef SWAP_H
+#define SWAP_H
+
+#include "elf.h"
+
+
+static inline uint32_t swap32_68K(uint32_t v)
+{
+#if !defined(__i386__)
+    return v;
+#else
+    return (
+            ((v & 0x000000ff) << 24) |
+            ((v & 0x0000ff00) << 8) |
+            ((v & 0x00ff0000) >> 8) |
+            ((v & 0xff000000) >> 24)
+            );
+#endif
+}
+
+
+static inline uint32_t swap32(uint32_t v)
+{
+#if defined(__i386__)
+    return v;
+#else
+    return (
+            ((v & 0x000000ff) << 24) |
+            ((v & 0x0000ff00) << 8) |
+            ((v & 0x00ff0000) >> 8) |
+            ((v & 0xff000000) >> 24)
+            );
+#endif
+}
+
+
+static inline uint16_t swap16_68K(uint16_t v)
+{
+#if !defined(__i386__)
+    return v;
+#else
+    return (
+            ((v & 0x00ff) << 8) |
+            ((v & 0xff00) >> 8)
+            );
+#endif
+}
+
+
+static inline uint16_t swap16(uint16_t v)
+{
+#if defined(__i386__)
+    return v;
+#else
+    return (
+            ((v & 0x00ff) << 8) |
+            ((v & 0xff00) >> 8)
+            );
+#endif
+}
+
+
+static inline void swap_ehdr(Elf32_Ehdr *ehdr)
+{
+    ehdr->e_type      = swap16(ehdr->e_type);
+    ehdr->e_machine   = swap16(ehdr->e_machine);
+    ehdr->e_version   = swap32(ehdr->e_version);
+    ehdr->e_entry     = swap32(ehdr->e_entry);
+    ehdr->e_phoff     = swap32(ehdr->e_phoff);
+    ehdr->e_shoff     = swap32(ehdr->e_shoff);
+    ehdr->e_flags     = swap32(ehdr->e_flags);
+    ehdr->e_ehsize    = swap16(ehdr->e_ehsize);
+    ehdr->e_phentsize = swap16(ehdr->e_phentsize);
+    ehdr->e_phnum     = swap16(ehdr->e_phnum);
+    ehdr->e_shentsize = swap16(ehdr->e_shentsize);
+    ehdr->e_shnum     = swap16(ehdr->e_shnum);
+    ehdr->e_shstrndx  = swap16(ehdr->e_shstrndx);
+}
+
+#endif
diff --git a/postlink/symbol.cc b/postlink/symbol.cc
new file mode 100644 (file)
index 0000000..9cca8e6
--- /dev/null
@@ -0,0 +1,91 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#include <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;
+}
diff --git a/postlink/symbol.h b/postlink/symbol.h
new file mode 100644 (file)
index 0000000..d5c9d3b
--- /dev/null
@@ -0,0 +1,66 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#ifndef SYMBOL_H
+#define SYMBOL_H
+
+#include <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
diff --git a/postlink/symboltable.cc b/postlink/symboltable.cc
new file mode 100644 (file)
index 0000000..1203905
--- /dev/null
@@ -0,0 +1,109 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#include "section.h"
+#include "symboltable.h"
+#include "stringtable.h"
+
+SymbolTable::SymbolTable(Image& newImage)
+    : Section(newImage)
+{ 
+    // symbol table with single empty symbol, unless replaced by read().
+    mSymbols.push_back(new Symbol(string(""), mImage.sections()[0], 0, 0, 0));
+}
+
+
+void SymbolTable::read(Elf32_Shdr *shdr)
+{ 
+    Section::read(shdr);
+
+    vector<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);
+}
diff --git a/postlink/symboltable.h b/postlink/symboltable.h
new file mode 100644 (file)
index 0000000..1050712
--- /dev/null
@@ -0,0 +1,66 @@
+/**********
+ * Copyright (c) 2004 Greg Parker.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ **********/
+
+#ifndef SYMBOLTABLE_H
+#define SYMBOLTABLE_H
+
+#include <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