179e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum/*
2c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    File:               CFMLateImport.c
3c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
4c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    Contains:           Implementation of CFM late import library.
5c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
6c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    Written by:         Quinn
7c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
8c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    Copyright:          Copyright � 1999 by Apple Computer, Inc., all rights reserved.
9c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
10c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            You may incorporate this Apple sample source code into your program(s) without
11c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            restriction. This Apple sample source code has been provided "AS IS" and the
12c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            responsibility for its operation is yours. You are not permitted to redistribute
13c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            this Apple sample source code as "Apple sample source code" after having made
14c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            changes. If you're going to re-distribute the source, we require that you make
15c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            it clear in the source that the code was descended from Apple sample source
16c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            code, but that you've made changes.
17c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
18c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    Change History (most recent first):
19c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
20c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    <13>     24/9/01    Quinn   Fixes to compile with C++ activated.
21c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    <12>     21/9/01    Quinn   [2710489] Fix typo in the comments for FragmentLookup.
22c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    <11>     21/9/01    Quinn   Changes for CWPro7 Mach-O build.
23c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    <10>     19/9/01    Quinn   Corrected implementation of kPEFRelocSmBySection. Added
24c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                implementations of kPEFRelocSetPosition and kPEFRelocLgByImport
25c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                (from code contributed by Eric Grant, Ned Holbrook, and Steve
26c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                Kalkwarf), although I can't test them yet.
27c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     <9>     19/9/01    Quinn   We now handle unpacked data sections, courtesy of some code from
28c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                Ned Holbrook.
29c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     <8>     19/9/01    Quinn   Minor fixes for the previous checkin. Updated some comments and
30c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                killed some dead code.
31c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     <7>     19/9/01    Quinn   Simplified API and implementation after a suggestion by Eric
32c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                Grant. You no longer have to CFM export a dummy function; you
33c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                can just pass in the address of your fragment's init routine.
34c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     <6>     15/2/01    Quinn   Modify compile-time warnings to complain if you try to build
35c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                this module into a Mach-O binary.
36c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     <5>      5/2/01    Quinn   Removed redundant assignment in CFMLateImportCore.
37c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     <4>    30/11/00    Quinn   Added comment about future of data symbols in CF.
38c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     <3>    16/11/00    Quinn   Allow symbol finding via a callback and use that to implement
39c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                CFBundle support.
40c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     <2>    18/10/99    Quinn   Renamed CFMLateImport to CFMLateImportLibrary to allow for
41c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                possible future API expansion.
42c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     <1>     15/6/99    Quinn   First checked in.
4379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum*/
4479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
4579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// To Do List:
4679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum//
4779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// o get rid of dependence on ANSI "string.h", but how?
4879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum//
4979e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// Done:
5079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum//
5179e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// � investigate alternative APIs, like an external lookup routine
5279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum//   renamed CFMLateImport to CFMLateImportLibrary to allow for
5379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum//   future expansion of the APIs for things like CFMLateImportSymbol
5479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// � test with non-zero fragment offset in the file
5579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// � test more with MPW fragments
5679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// � test data imports
5779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
5879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum/////////////////////////////////////////////////////////////////
5979e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
6079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// MoreIsBetter Setup
6179e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
6279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum//#include "MoreSetup.h"
6379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum#define MoreAssert(x) (true)
6479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum#define MoreAssertQ(x)
6579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
6679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// Mac OS Interfaces
6779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
6879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum#if ! MORE_FRAMEWORK_INCLUDES
69c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    #include <CodeFragments.h>
70c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    #include <PEFBinaryFormat.h>
7179e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum#endif
7279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
7379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// Standard C Interfaces
7479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
7579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum#include <string.h>
7679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
7779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// MIB Prototypes
7879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
7979e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum//#include "MoreInterfaceLib.h"
8079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum#define MoreBlockZero BlockZero
8179e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
8279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// Our Prototypes
8379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
8479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum#include "CFMLateImport.h"
8579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
8679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum/////////////////////////////////////////////////////////////////
8779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
8879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum#if TARGET_RT_MAC_MACHO
89c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    #error CFMLateImport is not suitable for use in a Mach-O project.
9079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum#elif !TARGET_RT_MAC_CFM || !TARGET_CPU_PPC
91c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    #error CFMLateImport has not been qualified for 68K or CFM-68K use.
9279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum#endif
9379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
9479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum/////////////////////////////////////////////////////////////////
9579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum#pragma mark ----- Utility Routines -----
9679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
9779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstatic OSStatus FSReadAtOffset(SInt16 refNum, SInt32 offset, SInt32 count, void *buffer)
98c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // A convenient wrapper around PBRead which has two advantages
99c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // over FSRead.  First, it takes count as a value parameter.
100c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Second, it reads from an arbitrary offset into the file,
101c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // which avoids a bunch of SetFPos calls.
102c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
103c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // I guess this should go into "MoreFiles.h", but I'm not sure
104c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // how we're going to integrate such a concept into MIB yet.
10579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
106c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    ParamBlockRec pb;
107c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
108c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    pb.ioParam.ioRefNum     = refNum;
109c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    pb.ioParam.ioBuffer     = (Ptr) buffer;
110c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    pb.ioParam.ioReqCount   = count;
111c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    pb.ioParam.ioPosMode    = fsFromStart;
112c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    pb.ioParam.ioPosOffset  = offset;
113c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
114c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    return PBReadSync(&pb);
11579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
11679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
11779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum/////////////////////////////////////////////////////////////////
11879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum#pragma mark ----- Late Import Engine -----
11979e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
12079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// This structure represents the core data structure of the late import
12179e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// engine.  It basically holds information about the fragment we're going
12279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// to fix up.  It starts off with the first three fields, which are
12379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// provided by the client.  Then, as we procede through the operation,
12479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// we fill out more fields.
12579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
12679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstruct FragToFixInfo {
127c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    CFragSystem7DiskFlatLocator         locator;                                // How to find the fragment's container.
128c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    CFragConnectionID                           connID;                                 // CFM connection to the fragment.
129c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    CFragInitFunction                           initRoutine;                    // The CFM init routine for the fragment.
130c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    PEFContainerHeader                          containerHeader;                // The CFM header, read in from the container.
131c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    PEFSectionHeader                            *sectionHeaders;                // The CFM section headers.  A pointer block containing an array of containerHeader.sectionCount elements.
132c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    PEFLoaderInfoHeader                         *loaderSection;                 // The entire CFM loader section in a pointer block.
133c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    SInt16                                              fileRef;                                // A read-only path to the CFM container.  We keep this here because one that one routine needs to read from the container.
134c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    void                                                *section0Base;                  // The base address of section 0, which we go through hoops to calculate.
135c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    void                                                *section1Base;                  // The base address of section 1, which we go through hoops to calculate.
136c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    Boolean                                             disposeSectionPointers; // See below.
13779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum};
13879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumtypedef struct FragToFixInfo FragToFixInfo;
13979e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
14079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// The disposeSectionPointers Boolean is designed for future cool VM
14179e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// support.  If VM is on, the entire code fragment is file mapped into
14279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// high memory, including the data we're forced to allocate the
14379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// sectionHeaders and loaderSection memory blocks to maintain.  If
14479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// we could find the address of the entire file mapped container,
14579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// we could access the information directly from there and thus
14679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// we wouldn't need to allocate (or dispose of) the memory blocks
14779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// for sectionHeaders and loaderSection.
14879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum//
14979e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// I haven't implemented this yet because a) I'm not sure how to do
15079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// it with documented APIs, and b) I couldn't be bothered, but
15179e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// disposeSectionPointers remains as vestigial support for the concept.
15279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
15379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstatic OSStatus ReadContainerBasics(FragToFixInfo *fragToFix)
154c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Reads some basic information from the container of the
155c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // fragment to fix and stores it in various fields of
156c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // fragToFix.  This includes:
157c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
158c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // o containerHeader -- The contain header itself.
159c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // o sectionHeaders  -- The array of section headers (in a newly allocated pointer block).
160c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // o loaderSection   -- The entire loader section (in a newly allocated pointer block).
161c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
162c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Also sets disposeSectionPointers to indicate whether
163c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // the last two pointers should be disposed of.
164c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
165c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Finally, it leaves the container file open for later
166c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // folks who want to read data from it.
16779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
168c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    OSStatus            err;
169c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt16              sectionIndex;
170c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    Boolean             found;
171c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
172c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFix != nil);
173c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFix->locator.fileSpec != nil);
174c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFix->connID != nil);
175c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFix->loaderSection == nil);
176c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFix->sectionHeaders == nil);
177c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFix->fileRef == 0);
178c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
179c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    fragToFix->disposeSectionPointers = true;
180c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
181c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Open up the file, read the container head, then read in
182c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // all the section headers, then go looking through the
183c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // section headers for the loader section (PEF defines
184c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // that there can be only one).
185c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
186c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    err = FSpOpenDF(fragToFix->locator.fileSpec, fsRdPerm, &fragToFix->fileRef);
187c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (err == noErr) {
188c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        err = FSReadAtOffset(fragToFix->fileRef,
189c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                        fragToFix->locator.offset,
190c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                        sizeof(fragToFix->containerHeader),
191c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                        &fragToFix->containerHeader);
192c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if (err == noErr) {
193c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            if (   fragToFix->containerHeader.tag1 != kPEFTag1
194c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                || fragToFix->containerHeader.tag2 != kPEFTag2
195c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                || fragToFix->containerHeader.architecture != kCompiledCFragArch
196c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                || fragToFix->containerHeader.formatVersion != kPEFVersion) {
197c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                err = cfragFragmentFormatErr;
198c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            }
199c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
200c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if (err == noErr) {
201c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            fragToFix->sectionHeaders = (PEFSectionHeader *) NewPtr(fragToFix->containerHeader.sectionCount * sizeof(PEFSectionHeader));
202c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            err = MemError();
203c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
204c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if (err == noErr) {
205c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            err = FSReadAtOffset(fragToFix->fileRef,
206c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                            fragToFix->locator.offset + sizeof(fragToFix->containerHeader),
207c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                            fragToFix->containerHeader.sectionCount * sizeof(PEFSectionHeader),
208c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                            fragToFix->sectionHeaders);
209c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
210c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if (err == noErr) {
211c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            sectionIndex = 0;
212c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            found = false;
213c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            while ( sectionIndex < fragToFix->containerHeader.sectionCount && ! found ) {
214c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                found = (fragToFix->sectionHeaders[sectionIndex].sectionKind == kPEFLoaderSection);
215c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                if ( ! found ) {
216c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    sectionIndex += 1;
217c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                }
218c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            }
219c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
220c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if (err == noErr && ! found) {
221c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            err = cfragNoSectionErr;
222c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
223c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
224c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        // Now read allocate a pointer block and read the loader section into it.
225c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
226c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if (err == noErr) {
227c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            fragToFix->loaderSection = (PEFLoaderInfoHeader *) NewPtr(fragToFix->sectionHeaders[sectionIndex].containerLength);
228c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            err = MemError();
229c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
230c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if (err == noErr) {
231c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            err = FSReadAtOffset(fragToFix->fileRef,
232c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                            fragToFix->locator.offset + fragToFix->sectionHeaders[sectionIndex].containerOffset,
233c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                            fragToFix->sectionHeaders[sectionIndex].containerLength,
234c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                            fragToFix->loaderSection);
235c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
236c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
237c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
238c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // No clean up.  The client must init fragToFix to zeros and then
239c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // clean up regardless of whether we return an error.
240c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
241c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    return err;
24279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
24379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
24479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstatic UInt32 DecodeVCountValue(const UInt8 *start, UInt32 *outCount)
245c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Given a pointer to the start of a variable length PEF value,
246c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // work out the value (in *outCount).  Returns the number of bytes
247c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // consumed by the value.
24879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
249c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt8 *                     bytePtr;
250c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt8                       byte;
251c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt32                      count;
252c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
253c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    bytePtr = (UInt8 *)start;
254c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
255c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Code taken from "PEFBinaryFormat.h".
256c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    count = 0;
257c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    do {
258c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        byte = *bytePtr++;
259c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        count = (count << kPEFPkDataVCountShift) | (byte & kPEFPkDataVCountMask);
260c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    } while ((byte & kPEFPkDataVCountEndMask) != 0);
261c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
262c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    *outCount = count;
263c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    return bytePtr - start;
26479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
26579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
26679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstatic UInt32 DecodeInstrCountValue(const UInt8 *inOpStart, UInt32 *outCount)
267c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Given a pointer to the start of an opcode (inOpStart), work out the
268c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // count argument for that opcode (*outCount).  Returns the number of
269c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // bytes consumed by the opcode and count combination.
27079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
271c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(inOpStart != nil);
272c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(outCount  != nil);
273c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
274c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (PEFPkDataCount5(*inOpStart) != 0)
275c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    {
276c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        // Simple case, count encoded in opcode.
277c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        *outCount = PEFPkDataCount5(*inOpStart);
278c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        return 1;
279c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
280c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    else
281c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    {
282c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        // Variable-length case.
283c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        return 1 + DecodeVCountValue(inOpStart + 1, outCount);
284c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
28579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
28679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
28779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstatic OSStatus UnpackPEFDataSection(const UInt8 * const packedData,   UInt32 packedSize,
288c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                           UInt8 * const unpackedData, UInt32 unpackedSize)
28979e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
290c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    OSErr                       err;
291c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt32                      offset;
292c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt8                       opCode;
293c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt8 *                     unpackCursor;
294c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
295c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(packedData != nil);
296c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(unpackedData != nil);
297c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(unpackedSize >= packedSize);
298c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
299c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // The following asserts assume that the client allocated the memory with NewPtr,
300c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // which may not always be true.  However, the asserts' value in preventing accidental
301c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // memory block overruns outweighs the possible maintenance effort.
302c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
303c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ( packedSize   == GetPtrSize( (Ptr) packedData  ) );
304c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ( unpackedSize == GetPtrSize( (Ptr) unpackedData) );
305c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
306c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    err          = noErr;
307c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    offset       = 0;
308c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    unpackCursor = unpackedData;
309c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    while (offset < packedSize) {
310c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        MoreAssertQ(unpackCursor < &unpackedData[unpackedSize]);
311c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
312c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        opCode = packedData[offset];
313c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
314c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        switch (PEFPkDataOpcode(opCode)) {
315c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            case kPEFPkDataZero:
316c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                {
317c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    UInt32                      count;
318c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
319c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    offset += DecodeInstrCountValue(&packedData[offset], &count);
320c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
321c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    MoreBlockZero(unpackCursor, count);
322c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    unpackCursor += count;
323c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                }
324c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                break;
325c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
326c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            case kPEFPkDataBlock:
327c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                {
328c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    UInt32                      blockSize;
329c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
330c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    offset += DecodeInstrCountValue(&packedData[offset], &blockSize);
331c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
332c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    BlockMoveData(&packedData[offset], unpackCursor, blockSize);
333c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    unpackCursor += blockSize;
334c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    offset += blockSize;
335c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                }
336c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                break;
337c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
338c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            case kPEFPkDataRepeat:
339c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                {
340c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    UInt32                      blockSize;
341c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    UInt32                      repeatCount;
342c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    UInt32  loopCounter;
343c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
344c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    offset += DecodeInstrCountValue(&packedData[offset], &blockSize);
345c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    offset += DecodeVCountValue(&packedData[offset], &repeatCount);
346c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    repeatCount += 1;                           // stored value is (repeatCount - 1)
347c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
348c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    for (loopCounter = 0; loopCounter < repeatCount; loopCounter++) {
349c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        BlockMoveData(&packedData[offset], unpackCursor, blockSize);
350c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        unpackCursor += blockSize;
351c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    }
352c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    offset += blockSize;
353c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                }
354c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                break;
355c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
356c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            case kPEFPkDataRepeatBlock:
357c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                {
358c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    UInt32                      commonSize;
359c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    UInt32                      customSize;
360c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    UInt32                      repeatCount;
361c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    const UInt8 *commonData;
362c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    const UInt8 *customData;
363c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    UInt32 loopCounter;
364c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
365c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    offset += DecodeInstrCountValue(&packedData[offset], &commonSize);
366c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    offset += DecodeVCountValue(&packedData[offset], &customSize);
367c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    offset += DecodeVCountValue(&packedData[offset], &repeatCount);
368c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
369c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    commonData = &packedData[offset];
370c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    customData = &packedData[offset + commonSize];
371c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
372c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    for (loopCounter = 0; loopCounter < repeatCount; loopCounter++) {
373c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        BlockMoveData(commonData, unpackCursor, commonSize);
374c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        unpackCursor += commonSize;
375c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        BlockMoveData(customData, unpackCursor, customSize);
376c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        unpackCursor += customSize;
377c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        customData += customSize;
378c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    }
379c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    BlockMoveData(commonData, unpackCursor, commonSize);
380c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    unpackCursor += commonSize;
381c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    offset += (repeatCount * (commonSize + customSize)) + commonSize;
382c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                }
383c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                break;
384c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
385c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            case kPEFPkDataRepeatZero:
386c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                {
387c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    UInt32                      commonSize;
388c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    UInt32                      customSize;
389c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    UInt32                      repeatCount;
390c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    const UInt8 *customData;
391c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    UInt32 loopCounter;
392c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
393c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    offset += DecodeInstrCountValue(&packedData[offset], &commonSize);
394c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    offset += DecodeVCountValue(&packedData[offset], &customSize);
395c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    offset += DecodeVCountValue(&packedData[offset], &repeatCount);
396c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
397c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    customData = &packedData[offset];
398c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
399c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    for (loopCounter = 0; loopCounter < repeatCount; loopCounter++) {
400c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        MoreBlockZero(unpackCursor, commonSize);
401c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        unpackCursor += commonSize;
402c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        BlockMoveData(customData, unpackCursor, customSize);
403c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        unpackCursor += customSize;
404c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        customData += customSize;
405c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    }
406c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    MoreBlockZero(unpackCursor, commonSize);
407c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    unpackCursor += commonSize;
408c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    offset += repeatCount * customSize;
409c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                }
410c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                break;
411c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
412c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            default:
413c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                #if MORE_DEBUG
414c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    DebugStr("\pUnpackPEFDataSection: Unexpected data opcode");
415c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                #endif
416c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                err = cfragFragmentCorruptErr;
417c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                goto leaveNow;
418c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                break;
419c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
420c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
421c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
42279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van RossumleaveNow:
423c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    return err;
42479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
42579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
426c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou/*      SetupSectionBaseAddresses Rationale
427c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    -----------------------------------
428c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
429c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    OK, here's where things get weird.  In order to run the relocation
430c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    engine, I need to be able to find the base address of an instantiated
431c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    section of the fragment we're fixing up given only its section number.
432c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    This isn't hard for CFM to do because it's the one that instantiated the
433c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    sections in the first place.  It's surprisingly difficult to do if
434c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    you're not CFM.  [And you don't have access to the private CFM APis for
435c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    doing it.]
436c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
437c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    [Alan Lillich is going to kill me when he reads this!  I should point out
438c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     that TVector's don't have to contain two words, they can be longer,
439c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     and that the second word isn't necessarily a TOC pointer, it's
440c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     just that the calling conventions require that it be put in the
441c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     TOC register when the code is called.
442c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
443c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     Furthermore, the code section isn't always section 0, and the data
444c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     section isn't always section 1, and there can be zero to many sections
445c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     of each type.
446c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
447c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     But these niceties are besides the point: I'm doing something tricky
448c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     because I don't have a nice API for getting section base addresses.
449c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou     If I had a nice API for doing that, none of this code would exist.
450c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    ]
451c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
452c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    The technique is very sneaky (thanks to Eric Grant).  The fragment to
453c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    fix necessarily has a CFM init routine (because it needs that routine
454c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    in order to capture the fragment location and connection ID).  Thus the
455c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    fragment to fix must have a TVector in its data section.  TVectors are
456c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    interesting because they're made up of two words.  The first is a pointer
457c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    to the code that implements the routine; the second is a pointer to the TOC
458c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    for the fragment that's exporting the TVector.  How TVectors are
459c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    created is interesting too.  On disk, a TVector consists of two words,
460c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    the first being the offset from the start of the code section to the
461c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    routine, the second being the offset from the start of the data section
462c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    to the TOC base.  When CFM prepares a TVector, it applies the following
463c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    transform:
464c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
465c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        tvector.codePtr = tvector.codeOffset + base of code section
466c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        tvector.tocPtr  = tvector.tocOffset  + base of data section
467c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
468c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    Now, you can reverse these questions to make them:
469c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
470c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        base of code section = tvector.codePtr - tvector.codeOffset
471c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        base of data section = tvector.dataPtr - tvector.dataOffset
472c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
473c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    So if you can find the relocated contents of the TVector and
474c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    find the original offsets that made up the TVector, you can then
475c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    calculate the base address of both the code and data sections.
476c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
477c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    Finding the relocated contents of the TVector is easy; I simply
478c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    require the client to pass in a pointer to its init routine.
479c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    A routine pointer is a TVector pointer, so you can just cast it
480c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    and extract the pair of words.
481c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
482c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    Finding the original offsets is a trickier.  My technique is to
483c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    look up the init routine in the fragment's loader info header.  This
484c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    yields the section number and offset where the init routine's unrelocated
485c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    TVector exists.  Once I have that, I can just read the unrelocated TVector
486c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    out of the file and extract the offsets.
48779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum*/
48879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
48979e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstruct TVector {
490c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    void *codePtr;
491c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    void *tocPtr;
49279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum};
49379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumtypedef struct TVector TVector;
49479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
49579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstatic OSStatus SetupSectionBaseAddresses(FragToFixInfo *fragToFix)
496c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // This routine initialises the section0Base and section1Base
497c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // base fields of fragToFix to the base addresses of the
498c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // instantiated fragment represented by the other fields
499c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // of fragToFix.  The process works in three states:
500c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
501c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // 1.       Find the contents of the relocated TVector of the
502c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //      fragment's initialisation routine, provided to us by
503c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //      the caller.
504c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
505c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // 2.       Find the contents of the non-relocated TVector by
506c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //      looking it up in the PEF loader info header and then
507c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //      using that to read the TVector contents from disk.
508c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //      This yields the offsets from the section bases for
509c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //      the init routine.
510c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
511c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // 3.       Subtract 2 from 3.
51279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
513c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    OSStatus                            err;
514c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    TVector *                           relocatedExport;
515c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    SInt32                              initSection;
516c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt32                              initOffset;
517c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    PEFSectionHeader *          initSectionHeader;
518c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    Ptr                                         packedDataSection;
519c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    Ptr                                         unpackedDataSection;
520c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    TVector                             originalOffsets;
521c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
522c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    packedDataSection   = nil;
523c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    unpackedDataSection = nil;
524c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
525c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Step 1.
526c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
527c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // First find the init routine's TVector, which gives us the relocated
528c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // offsets of the init routine into the data and code sections.
529c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
530c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    relocatedExport = (TVector *) fragToFix->initRoutine;
531c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
532c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Step 2.
533c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
534c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Now find the init routine's TVector's offsets in the data section on
535c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // disk.  This gives us the raw offsets from the data and code section
536c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // of the beginning of the init routine.
537c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
538c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    err = noErr;
539c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    initSection = fragToFix->loaderSection->initSection;
540c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    initOffset  = fragToFix->loaderSection->initOffset;
541c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (initSection == -1) {
542c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        err = cfragFragmentUsageErr;
543c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
544c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (err == noErr) {
545c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        MoreAssertQ( initSection >= 0 );                        // Negative indexes are pseudo-sections which are just not allowed!
546c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        MoreAssertQ( initSection < fragToFix->containerHeader.sectionCount );
547c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
548c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        initSectionHeader = &fragToFix->sectionHeaders[initSection];
549c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
550c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        // If the data section is packed, unpack it to a temporary buffer and then get the
551c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        // original offsets from that buffer.  If the data section is unpacked, just read
552c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        // the original offsets directly off the disk.
553c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
554c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if ( initSectionHeader->sectionKind == kPEFPackedDataSection ) {
555c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
556c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            // Allocate space for packed and unpacked copies of the section.
557c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
558c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            packedDataSection = NewPtr(initSectionHeader->containerLength);
559c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            err = MemError();
560c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
561c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            if (err == noErr) {
562c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                unpackedDataSection = NewPtr(initSectionHeader->unpackedLength);
563c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                err = MemError();
564c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            }
565c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
566c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            // Read the contents of the packed section.
567c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
568c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            if (err == noErr) {
569c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                err = FSReadAtOffset(                   fragToFix->fileRef,
570c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                fragToFix->locator.offset
571c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                + initSectionHeader->containerOffset,
572c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                initSectionHeader->containerLength,
573c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                packedDataSection);
574c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            }
575c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
576c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            // Unpack the data into the unpacked section.
577c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
578c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            if (err == noErr) {
579c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                err = UnpackPEFDataSection( (UInt8 *) packedDataSection,   initSectionHeader->containerLength,
580c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                            (UInt8 *) unpackedDataSection, initSectionHeader->unpackedLength);
581c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            }
582c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
583c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            // Extract the init routine's TVector from the unpacked section.
584c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
585c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            if (err == noErr) {
586c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                BlockMoveData(unpackedDataSection + initOffset, &originalOffsets, sizeof(TVector));
587c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            }
588c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
589c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        } else {
590c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            MoreAssertQ(fragToFix->sectionHeaders[initSection].sectionKind == kPEFUnpackedDataSection);
591c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            err = FSReadAtOffset(fragToFix->fileRef,
592c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                            fragToFix->locator.offset
593c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                            + fragToFix->sectionHeaders[initSection].containerOffset
594c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                            + initOffset,
595c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                            sizeof(TVector),
596c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                            &originalOffsets);
597c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
598c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
599c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
600c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Step 3.
601c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
602c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Do the maths to subtract the unrelocated offsets from the current address
603c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // to get the base address.
604c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
605c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (err == noErr) {
606c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        fragToFix->section0Base = ((char *) relocatedExport->codePtr) - (UInt32) originalOffsets.codePtr;
607c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        fragToFix->section1Base = ((char *) relocatedExport->tocPtr)  - (UInt32) originalOffsets.tocPtr;
608c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
609c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
610c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Clean up.
611c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
612c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (packedDataSection != nil) {
613c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        DisposePtr(packedDataSection);
614c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        MoreAssertQ( MemError() == noErr );
615c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
616c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (unpackedDataSection != nil) {
617c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        DisposePtr(unpackedDataSection);
618c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        MoreAssertQ( MemError() == noErr );
619c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
620c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    return err;
62179e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
62279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
62379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstatic void *GetSectionBaseAddress(const FragToFixInfo *fragToFix, UInt16 sectionIndex)
624c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // This routine returns the base of the instantiated section
625c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // whose index is sectionIndex.  This routine is the evil twin
626c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // of SetupSectionBaseAddresses.  It simply returns the values
627c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // for section 0 and 1 that we derived in SetupSectionBaseAddresses.
628c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // In a real implementation, this routine would call CFM API
629c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // to get this information, and SetupSectionBaseAddresses would
630c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // not exist, but CFM does not export the necessary APIs to
631c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // third parties.
63279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
633c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    void *result;
634c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
635c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFix != nil);
636c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFix->containerHeader.tag1 == kPEFTag1);
637c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
638c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    switch (sectionIndex) {
639c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        case 0:
640c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            result = fragToFix->section0Base;
641c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            break;
642c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        case 1:
643c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            result = fragToFix->section1Base;
644c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            break;
645c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        default:
646c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            result = nil;
647c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            break;
648c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
649c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    return result;
65079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
65179e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
65279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
65379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstatic OSStatus FindImportLibrary(PEFLoaderInfoHeader *loaderSection, const char *libraryName, PEFImportedLibrary **importLibrary)
654c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // This routine finds the import library description (PEFImportedLibrary)
655c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // for the import library libraryName in the PEF loader section.
656c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // It sets *importLibrary to the address of the description.
65779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
658c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    OSStatus                            err;
659c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt32                              librariesRemaining;
660c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    PEFImportedLibrary          *thisImportLibrary;
661c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    Boolean                             found;
662c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
663c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(loaderSection != nil);
664c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(libraryName != nil);
665c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(importLibrary != nil);
666c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
667c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Loop through each import library looking for a matching name.
668c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
669c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Initialise thisImportLibrary to point to the byte after the
670c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // end of the loader section's header.
671c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
672c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    thisImportLibrary = (PEFImportedLibrary *) (loaderSection + 1);
673c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    librariesRemaining = loaderSection->importedLibraryCount;
674c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    found = false;
675c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    while ( librariesRemaining > 0 && ! found ) {
676c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        // PEF defines that import library names will have
677c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        // a null terminator, so we can just use strcmp.
678c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        found = (strcmp( libraryName,
679c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                        ((char *)loaderSection)
680c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                        + loaderSection->loaderStringsOffset
681c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                        + thisImportLibrary->nameOffset) == 0);
682c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        // *** Remove ANSI strcmp eventually.
683c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if ( ! found ) {
684c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            thisImportLibrary += 1;
685c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            librariesRemaining -= 1;
686c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
687c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
688c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
689c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (found) {
690c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        *importLibrary = thisImportLibrary;
691c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        err = noErr;
692c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    } else {
693c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        *importLibrary = nil;
694c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        err = cfragNoLibraryErr;
695c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
696c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    return err;
69779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
69879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
69979e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstatic OSStatus LookupSymbol(CFMLateImportLookupProc lookup, void *refCon,
700c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                        PEFLoaderInfoHeader *loaderSection,
701c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                        UInt32 symbolIndex,
702c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                        UInt32 *symbolValue)
703c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // This routine is used to look up a symbol during relocation.
704c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // "lookup" is a client callback and refCon is its argument.
705c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Typically refCon is the CFM connection to the library that is
706c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // substituting for the weak linked library.  loaderSection
707c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // is a pointer to the loader section of the fragment to fix up.
708c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // symbolIndex is the index of the imported symbol in the loader section.
709c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // The routine sets the word pointed to by symbolValue to the
710c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // value of the symbol.
711c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
712c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // The routine works by using symbolIndex to index into the imported
713c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // symbol table to find the offset of the symbol's name in the string
714c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // table.  It then looks up the symbol by calling the client's "lookup"
715c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // function and passes the resulting symbol address back in symbolValue.
71679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
717c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    OSStatus                            err;
718c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt32                              *importSymbolTable;
719c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt32                              symbolStringOffset;
720c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    Boolean                             symbolIsWeak;
721c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    CFragSymbolClass            symbolClass;
722c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    char                                *symbolStringAddress;
723c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    Str255                              symbolString;
724c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
725c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(lookup != nil);
726c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(loaderSection != nil);
727c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(symbolIndex < loaderSection->totalImportedSymbolCount);
728c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(symbolValue != nil);
729c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
730c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Find the base of the imported symbol table.
731c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
732c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    importSymbolTable = (UInt32 *)(((char *)(loaderSection + 1)) + (loaderSection->importedLibraryCount * sizeof(PEFImportedLibrary)));
733c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
734c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Grab the appropriate entry out of the table and
735c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // extract the information from that entry.
736c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
737c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    symbolStringOffset = importSymbolTable[symbolIndex];
738c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    symbolClass = PEFImportedSymbolClass(symbolStringOffset);
739c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    symbolIsWeak = ((symbolClass & kPEFWeakImportSymMask) != 0);
740c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    symbolClass = symbolClass & ~kPEFWeakImportSymMask;
741c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    symbolStringOffset = PEFImportedSymbolNameOffset(symbolStringOffset);
742c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
743c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Find the string for the symbol in the strings table and
744c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // extract it from the table into a Pascal string on the stack.
745c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
746c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    symbolStringAddress = ((char *)loaderSection) + loaderSection->loaderStringsOffset + symbolStringOffset;
747c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    symbolString[0] = strlen(symbolStringAddress);              // *** remove ANSI strlen
748c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    BlockMoveData(symbolStringAddress, &symbolString[1], symbolString[0]);
749c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
750c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Look up the symbol in substitute library.  If it fails, return
751c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // a 0 value and check whether the error is fatal (a strong linked
752c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // symbol) or benign (a weak linked symbol).
753c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
754c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    err = lookup(symbolString, symbolClass, (void **) symbolValue, refCon);
755c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (err != noErr) {
756c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        *symbolValue = 0;
757c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if (symbolIsWeak) {
758c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            err = noErr;
759c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
760c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
761c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    return err;
76279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
76379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
76479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// The EngineState structure encapsulates all of the persistent state
76579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// of the CFM relocation engine virtual machine.  I originally defined
76679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// this structure so I could pass the state around between routines
76779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// that implement various virtual opcodes, however I later worked
76879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// out that the relocation was sufficiently simple that I could put it
76979e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// in in one routine.  Still, I left the state in this structure in
77079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// case I ever need to reverse that decision.  It's also a convenient
77179e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// instructional design.
77279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
77379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstruct EngineState {
774c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt32 currentReloc;                // Index of current relocation opcodes
775c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt32 terminatingReloc;            // Index of relocation opcodes which terminates relocation
776c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt32 *sectionBase;                // Start of the section
777c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt32 *relocAddress;               // Address within the section where the relocations are to be performed
778c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt32 importIndex;                         // Symbol index, which is used to access an imported symbol's address
779c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    void  *sectionC;                            // Memory address of an instantiated section within the PEF container; this variable is used by relocation opcodes that relocate section addresses
780c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    void  *sectionD;                            // Memory address of an instantiated section within the PEF container; this variable is used by relocation opcodes that relocate section addresses
78179e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum};
78279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumtypedef struct EngineState EngineState;
78379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
78479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// Note:
78579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// If I ever have to support the repeat opcodes, I'll probably
78679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// have to add a repeat counter to EngineState.
78779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
78879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstatic OSStatus InitEngineState(const FragToFixInfo *fragToFix,
789c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                UInt16 relocHeaderIndex,
790c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                EngineState *state)
791c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // This routine initialises the engine state suitably for
792c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // running the relocation opcodes for the section whose
793c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // index is relocHeaderIndex.  relocHeaderIndex is not a
794c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // a section number.  See the comment where it's used below
795c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // for details.  The routine basically fills out all the fields
796c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // in the EngineState structure as described by
797c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // "Mac OS Runtime Architectures".
79879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
799c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    OSStatus err;
800c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    PEFLoaderRelocationHeader *relocHeader;
801c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
802c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFix != nil);
803c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(state != nil);
804c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
805c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // This bit is tricky.  relocHeaderIndex is an index into the relocation
806c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // header table, starting at relocSectionCount (which is in the loader
807c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // section header) for the first relocated section and decrementing
808c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // down to 1 for the last relocated section.  I find the relocation
809c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // header by using relocHeaderIndex as a index backwards from the
810c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // start of the relocation opcodes (ie relocInstrOffset).  If you
811c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // look at the diagram of the layout of the container in
812c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // "PEFBinaryFormat.h", you'll see that the relocation opcodes
813c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // immediately follow the relocation headers.
814c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
815c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // I did this because the alternative (starting at the loader
816c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // header and stepping past the import library table and the
817c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // import symbol table) was a pain.
818c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
819c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    relocHeader = (PEFLoaderRelocationHeader *) (((char *) fragToFix->loaderSection) + fragToFix->loaderSection->relocInstrOffset - relocHeaderIndex * sizeof(PEFLoaderRelocationHeader));
820c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
821c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(relocHeader->reservedA == 0);                   // PEF spec says it must be; we check to try to catch bugs in calculation of relocHeader
822c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
823c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    state->currentReloc = relocHeader->firstRelocOffset;
824c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    state->terminatingReloc = relocHeader->firstRelocOffset + relocHeader->relocCount;
825c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    state->sectionBase = (UInt32 *) GetSectionBaseAddress(fragToFix, relocHeader->sectionIndex);
826c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    state->relocAddress = state->sectionBase;
827c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    state->importIndex = 0;
828c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
829c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // From "Mac OS Runtime Architectures":
830c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
831c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // The sectionC and sectionD variables actually contain the
832c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // memory address of an instantiated section minus the
833c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // default address for that section. The default address for a
834c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // section is contained in the defaultAddress field of the
835c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // section header. However, in almost all cases the default
836c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // address should be 0, so the simplified definition suffices.
837c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
838c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // In the debug version, we drop into MacsBug if this weird case
839c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // ever executes because it's more likely we made a mistake than
840c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // we encountered a section with a default address.
841c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
842c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    state->sectionC = GetSectionBaseAddress(fragToFix, 0);
843c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (state->sectionC != nil) {
844c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        #if MORE_DEBUG
845c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            if (fragToFix->sectionHeaders[0].defaultAddress != 0) {
846c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                DebugStr("\pInitEngineState: Executing weird case.");
847c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            }
848c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        #endif
849c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        (char *) state->sectionC -= fragToFix->sectionHeaders[0].defaultAddress;
850c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
851c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    state->sectionD = GetSectionBaseAddress(fragToFix, 1);
852c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (state->sectionD != nil) {
853c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        #if MORE_DEBUG
854c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            if (fragToFix->sectionHeaders[1].defaultAddress != 0) {
855c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                DebugStr("\pInitEngineState: Executing weird case.");
856c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            }
857c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        #endif
858c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        (char *) state->sectionD -= fragToFix->sectionHeaders[1].defaultAddress;
859c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
860c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
861c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    err = noErr;
862c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (state->relocAddress == nil) {
863c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        err = cfragFragmentUsageErr;
864c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
865c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    return err;
86679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
86779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
86879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// kPEFRelocBasicOpcodes is a table that maps the top 7 bits of the opcode
86979e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// to a fundamental action.  It's contents are defined for me in "PEFBinaryFormat.h",
87079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum// which is really convenient.
87179e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
87279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstatic UInt8 kPEFRelocBasicOpcodes[kPEFRelocBasicOpcodeRange] = { PEFMaskedBasicOpcodes };
87379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
874c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitroustatic OSStatus RunRelocationEngine(const FragToFixInfo *fragToFix,
875c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                PEFImportedLibrary  *importLibrary,
876c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                CFMLateImportLookupProc lookup, void *refCon)
877c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // This is where the rubber really hits the.  Given a fully
878c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // populated fragToFix structure, the import library description
879c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // of the weak imported library we're resolving, and a connection
880c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // to the library we're going to substitute it, re-execute the
881c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // relocation instructions (CFM has already executed them once)
882c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // but only *do* instructions (ie store the change to the data section)
883c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // that CFM skipped because the weak symbols were missing.
88479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
885c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    OSStatus            err;
886c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    EngineState         state;
887c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt16              sectionsLeftToRelocate;
888c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt32              totalRelocs;
889c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt16              *relocInstrTable;
890c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    UInt16              opCode;
891c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
892c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFix != nil);
893c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFix->containerHeader.tag1 == kPEFTag1);
894c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFix->sectionHeaders != nil);
895c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFix->loaderSection != nil);
896c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFix->section0Base != nil);        // Technically, having a nil for these two is not a problem, ...
897a52b567a3f36004cc48f91feeb708548c20e57d5Martin Panter    MoreAssertQ(fragToFix->section1Base != nil);        // but in practice it a wildly deviant case and we should know about it.
898c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(importLibrary != nil);
899c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(lookup != nil);
900c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
901c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Before entering the loop, work out some information in advance.
902c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
903c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // totalRelocs is only used for debugging, to make sure our
904c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // relocation PC (state.currentReloc) doesn't run wild.
905c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
906c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    totalRelocs = (fragToFix->loaderSection->loaderStringsOffset - fragToFix->loaderSection->relocInstrOffset) / sizeof(UInt16);
907c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
908c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // relocInstrTable is the base address of the table of relocation
909c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // instructions in the fragment to fix.
910c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
911c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    relocInstrTable = (UInt16 *)((char *) fragToFix->loaderSection + fragToFix->loaderSection->relocInstrOffset);
912c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
913c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // sectionsLeftToRelocate is the loop counter for the outer loop.
914c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
915c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFix->loaderSection->relocSectionCount <= 0x0FFFF);
916c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    sectionsLeftToRelocate = fragToFix->loaderSection->relocSectionCount;
917c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
918c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Now let's run the relocation engine.  We run it once per
919c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // section in the table.  Each time around, we init the engine
920c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // and then loop again, this time executing individual opcodes.
921c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // The opcode loop terminates when the relocation PC
922c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // (state.currentReloc) hits the final opcode (state.terminatingReloc).
923c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
924c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Note:
925c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // One design decision I made was to totally re-init the engine state
926c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // for each section.  The CFM spec is unclear as to whether you're supposed
927c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // to totally re-init the engine state, or just re-init the section-specific
928c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // state (ie currentReloc, terminatingReloc, and relocAddress).  I hope this
929c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // is correct, but it's hard to test without having a fragment with multiple
930c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // relocated sections, which is difficult to create.
931c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
932c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // How do I decide which opcodes should be effective (ie make changes to
933c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // the section being relocated) and which opcodes should just be executed
934c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // for their side effects (ie updated state.relocAddress or state.importIndex)?
935c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // The answer is both simple and subtle.  Opcodes whose actions are dependent
936c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // on a symbol that was in the weak linked library are effective, those that
937c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // an independent of those symbols are not.  The only opcodes that use
938c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // symbolic values are kPEFRelocImportRun and kPEFRelocSmByImport, and
939c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // these are only if the symbol is in the weak linked library.
940c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // All other cases are executed for their side effects only.
941c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
942c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // How do I determine if a symbol is in the weak linked library?
943c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Well I know the symbol's index and I know the lower bound and count
944c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // of the symbols in the weak linked library, so I just do a simple
945c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // bounds test, ie
946c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
947c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //   firstImportedSymbol <= importIndex < firstImportedSymbol + importedSymbolCount
948c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
949c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // From this code, it's relatively easy to see which relocation opcodes
950c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // aren't implemented.  If you ever encounter one, you'll find yourself
951c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // in MacsBug with a message telling you which opcode was found.  The
952c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // two big groups of opcodes I skipped were the large format opcodes
953c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // and the repeating opcodes.  I skipped them because:
954c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
955c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // a) I haven't got a way to generate them in a PEF container that I can
956c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //    test against. Without that, there's no way I could be assured that
957c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //    the code worked.
958c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
959c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // b) I'm lazy.
960c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
961c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    err = noErr;
962c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    while ( sectionsLeftToRelocate > 0 ) {
963c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        err = InitEngineState(fragToFix, sectionsLeftToRelocate, &state);
964c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if (err != noErr) {
965c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            goto leaveNow;
966c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
967c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
968c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        while ( state.currentReloc != state.terminatingReloc ) {
969c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
970c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            MoreAssertQ( state.currentReloc < totalRelocs );
971c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
972c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            opCode = relocInstrTable[state.currentReloc];
973c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            switch ( PEFRelocBasicOpcode(opCode) ) {
974c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocBySectDWithSkip:
975c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    {
976c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        UInt16 skipCount;
977c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        UInt16 relocCount;
978c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
979c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        skipCount = ((opCode >> 6) & 0x00FF);
980c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        relocCount = (opCode & 0x003F);
981c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        state.relocAddress += skipCount;
982c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        state.relocAddress += relocCount;
983c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    }
984c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
985c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocBySectC:
986c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocBySectD:
987c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    {
988c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        UInt16 runLength;
989c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
990c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        runLength = (opCode & 0x01FF) + 1;
991c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        state.relocAddress += runLength;
992c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    }
993c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
994c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocTVector12:
995c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    {
996c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        UInt16 runLength;
997c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
998c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        runLength = (opCode & 0x01FF) + 1;
999c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        state.relocAddress += (runLength * 3);
1000c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    }
1001c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
1002c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocTVector8:
1003c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocVTable8:
1004c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    {
1005c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        UInt16 runLength;
1006c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1007c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        runLength = (opCode & 0x01FF) + 1;
1008c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        state.relocAddress += (runLength * 2);
1009c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    }
1010c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
1011c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocImportRun:
1012c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    {
1013c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        UInt32 symbolValue;
1014c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        UInt16 runLength;
1015c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1016c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        runLength = (opCode & 0x01FF) + 1;
1017c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        while (runLength > 0) {
1018c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            if ( state.importIndex >= importLibrary->firstImportedSymbol && state.importIndex < (importLibrary->firstImportedSymbol + importLibrary->importedSymbolCount) ) {
1019c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                err = LookupSymbol(lookup, refCon, fragToFix->loaderSection, state.importIndex, &symbolValue);
1020c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                if (err != noErr) {
1021c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                    goto leaveNow;
1022c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                }
1023c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                *(state.relocAddress) += symbolValue;
1024c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            }
1025c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            state.importIndex += 1;
1026c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            state.relocAddress += 1;
1027c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            runLength -= 1;
1028c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        }
1029c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    }
1030c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
1031c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocSmByImport:
1032c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    {
1033c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        UInt32 symbolValue;
1034c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        UInt32 index;
1035c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1036c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        index = (opCode & 0x01FF);
1037c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        if ( index >= importLibrary->firstImportedSymbol && index < (importLibrary->firstImportedSymbol + importLibrary->importedSymbolCount) ) {
1038c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            err = LookupSymbol(lookup, refCon, fragToFix->loaderSection, index, &symbolValue);
1039c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            if (err != noErr) {
1040c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                goto leaveNow;
1041c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            }
1042c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            *(state.relocAddress) += symbolValue;
1043c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        }
1044c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        state.importIndex = index + 1;
1045c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        state.relocAddress += 1;
1046c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    }
1047c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
1048c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocSmSetSectC:
1049c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    {
1050c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        UInt32 index;
1051c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1052c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        index = (opCode & 0x01FF);
1053c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        state.sectionC = GetSectionBaseAddress(fragToFix, index);
1054c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        MoreAssertQ(state.sectionC != nil);
1055c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    }
1056c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
1057c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocSmSetSectD:
1058c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    {
1059c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        UInt32 index;
1060c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1061c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        index = (opCode & 0x01FF);
1062c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        state.sectionD = GetSectionBaseAddress(fragToFix, index);
1063c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        MoreAssertQ(state.sectionD != nil);
1064c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    }
1065c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
1066c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocSmBySection:
1067c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    state.relocAddress += 1;
1068c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
1069c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocIncrPosition:
1070c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    {
1071c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        UInt16 offset;
1072c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1073c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        offset = (opCode & 0x0FFF) + 1;
1074c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        ((char *) state.relocAddress) += offset;
1075c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    }
1076c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
1077c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocSmRepeat:
1078c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    #if MORE_DEBUG
1079c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        DebugStr("\pRunRelocationEngine: kPEFRelocSmRepeat not yet implemented");
1080c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    #endif
1081c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    err = unimpErr;
1082c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    goto leaveNow;
1083c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
1084c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocSetPosition:
1085c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    {
1086c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        UInt32 offset;
1087c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1088c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        // Lot's of folks have tried various interpretations of the description of
1089c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        // this opCode in "Mac OS Runtime Architectures" (which states "This instruction
1090c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        // sets relocAddress to the address of the section offset offset."  *smile*).
1091c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        // I eventually dug into the CFM source code to find my interpretation, which
1092c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        // I believe is correct.  The key point is tht the offset is relative to
1093c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        // the start of the section for which these relocations are being performed.
1094c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1095c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        // Skip to next reloc word, which is the second chunk of the offset.
1096c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1097c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        state.currentReloc += 1;
1098c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1099c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        // Extract offset based on the most significant 10 bits in opCode and
1100c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        // the next significant 16 bits in the next reloc word.
1101c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1102c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        offset = PEFRelocSetPosFullOffset(opCode, relocInstrTable[state.currentReloc]);
1103c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1104c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        state.relocAddress = (UInt32 *) ( ((char *) state.sectionBase) + offset);
1105c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    }
1106c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
1107c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocLgByImport:
1108c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    {
1109c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        UInt32 symbolValue;
1110c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        UInt32 index;
1111c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1112c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        // Get the 26 bit symbol index from the current and next reloc words.
1113c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1114c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        state.currentReloc += 1;
1115c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        index = PEFRelocLgByImportFullIndex(opCode, relocInstrTable[state.currentReloc]);
1116c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1117c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        if ( index >= importLibrary->firstImportedSymbol && index < (importLibrary->firstImportedSymbol + importLibrary->importedSymbolCount) ) {
1118c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            err = LookupSymbol(lookup, refCon, fragToFix->loaderSection, index, &symbolValue);
1119c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            if (err != noErr) {
1120c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                goto leaveNow;
1121c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            }
1122c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                            *(state.relocAddress) += symbolValue;
1123c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        }
1124c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        state.importIndex = index + 1;
1125c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        state.relocAddress += 1;
1126c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    }
1127c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
1128c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocLgRepeat:
1129c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    #if MORE_DEBUG
1130c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        DebugStr("\pRunRelocationEngine: kPEFRelocLgRepeat not yet implemented");
1131c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    #endif
1132c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    err = unimpErr;
1133c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    goto leaveNow;
1134c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
1135c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocLgSetOrBySection:
1136c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    #if MORE_DEBUG
1137c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                        DebugStr("\pRunRelocationEngine: kPEFRelocLgSetOrBySection not yet implemented");
1138c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    #endif
1139c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    err = unimpErr;
1140c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    goto leaveNow;
1141c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
1142c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                case kPEFRelocUndefinedOpcode:
1143c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    err = cfragFragmentCorruptErr;
1144c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    goto leaveNow;
1145c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
1146c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                default:
1147c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    MoreAssertQ(false);
1148c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    err = cfragFragmentCorruptErr;
1149c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    goto leaveNow;
1150c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                    break;
1151c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            }
1152c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            state.currentReloc += 1;
1153c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
1154c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1155c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        sectionsLeftToRelocate -= 1;
1156c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
115779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
115879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van RossumleaveNow:
1159c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    return err;
116079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
116179e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
116279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumextern pascal OSStatus CFMLateImportCore(const CFragSystem7DiskFlatLocator *fragToFixLocator,
1163c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                CFragConnectionID fragToFixConnID,
1164c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                CFragInitFunction fragToFixInitRoutine,
1165c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                ConstStr255Param weakLinkedLibraryName,
1166c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                CFMLateImportLookupProc lookup,
1167c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                void *refCon)
1168c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // See comments in interface part.
116979e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
1170c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    OSStatus err;
1171c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    OSStatus junk;
1172c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    FragToFixInfo fragToFix;
1173c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    PEFImportedLibrary *importLibrary;
1174c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    char weakLinkedLibraryNameCString[256];
1175c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1176c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFixLocator != nil);
1177c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFixConnID != nil);
1178c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(fragToFixInitRoutine != nil);
1179c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(weakLinkedLibraryName != nil);
1180c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(lookup != nil);
1181c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1182c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Fill out the bits of fragToFix which are passed in
1183c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // by the client.
1184c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1185c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreBlockZero(&fragToFix, sizeof(fragToFix));
1186c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    fragToFix.locator = *fragToFixLocator;
1187c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    fragToFix.connID  = fragToFixConnID;
1188c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    fragToFix.initRoutine = fragToFixInitRoutine;
1189c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1190c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Make a C string from weakLinkedLibraryName.
1191c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1192c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    BlockMoveData(weakLinkedLibraryName + 1, weakLinkedLibraryNameCString, weakLinkedLibraryName[0]);
1193c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    weakLinkedLibraryNameCString[weakLinkedLibraryName[0]] = 0;
1194c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1195c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Get the basic information from the fragment.
1196c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Fills out the containerHeader, sectionHeaders, loaderSection and fileRef fields
1197c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // of fragToFix.
1198c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1199c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    err = ReadContainerBasics(&fragToFix);
1200c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1201c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Set up the base address fields in fragToFix (ie section0Base and section1Base)
1202c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // by looking up our init routine (fragToFix.initRoutine) and subtracting
1203c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // away the section offsets (which we get from the disk copy of the section)
1204c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // to derive the bases of the sections themselves.
1205c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1206c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (err == noErr) {
1207c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        err = SetupSectionBaseAddresses(&fragToFix);
1208c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
1209c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1210c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Look inside the loader section for the import library description
1211c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // of weakLinkedLibraryName.  We need this to know the range of symbol
1212c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // indexes we're going to fix up.
1213c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1214c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (err == noErr) {
1215c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        err = FindImportLibrary(fragToFix.loaderSection, weakLinkedLibraryNameCString, &importLibrary);
1216c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
1217c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1218c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Do a quick check to ensure that the library was actually imported weak.
1219c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // If it wasn't, it doesn't make much sense to resolve its weak imports
1220c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // later on.  Resolving them again is likely to be bad.
1221c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1222c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (err == noErr) {
1223c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if ((importLibrary->options & kPEFWeakImportLibMask) == 0) {
1224c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            err = cfragFragmentUsageErr;
1225c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
1226c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
1227c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1228c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Now run the main relocation engine.
1229c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1230c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (err == noErr) {
1231c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        err = RunRelocationEngine(&fragToFix, importLibrary, lookup, refCon);
1232c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
1233c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1234c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Clean up.
1235c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1236c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (fragToFix.disposeSectionPointers) {
1237c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if (fragToFix.fileRef != 0) {
1238c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            junk = FSClose(fragToFix.fileRef);
1239c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            MoreAssertQ(junk == noErr);
1240c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
1241c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if (fragToFix.loaderSection != nil) {
1242c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            DisposePtr( (Ptr) fragToFix.loaderSection);
1243c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            MoreAssertQ(MemError() == noErr);
1244c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
1245c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if (fragToFix.sectionHeaders != nil) {
1246c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            DisposePtr( (Ptr) fragToFix.sectionHeaders);
1247c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            MoreAssertQ(MemError() == noErr);
1248c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
1249c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
1250c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    return err;
125179e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
125279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
125379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstatic pascal OSStatus FragmentLookup(ConstStr255Param symName, CFragSymbolClass symClass,
1254c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                        void **symAddr, void *refCon)
1255c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // This is the CFMLateImportLookupProc callback used when
1256c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // late importing from a CFM shared library.
125779e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
1258c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    OSStatus err;
1259c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    CFragConnectionID connIDToImport;
1260c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    CFragSymbolClass  foundSymClass;
1261c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1262c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(symName != nil);
1263c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(symAddr != nil);
1264c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(refCon  != nil);
1265c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1266c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    connIDToImport = (CFragConnectionID) refCon;
1267c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1268c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Shame there's no way to validate that connIDToImport is valid.
1269c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1270c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    err = FindSymbol(connIDToImport, symName, (Ptr *) symAddr, &foundSymClass);
1271c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (err == noErr) {
1272c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        // If the symbol isn't of the right class, we act like we didn't
1273c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        // find it, but also assert in the debug build because weird things
1274c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        // are afoot.
1275c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if (foundSymClass != symClass) {
1276c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            MoreAssertQ(false);
1277c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            *symAddr = nil;
1278c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            err = cfragNoSymbolErr;
1279c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
1280c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
1281c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    return err;
128279e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
128379e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
128479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumextern pascal OSStatus CFMLateImportLibrary(const CFragSystem7DiskFlatLocator *fragToFixLocator,
1285c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                CFragConnectionID fragToFixConnID,
1286c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                CFragInitFunction fragToFixInitRoutine,
1287c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                ConstStr255Param weakLinkedLibraryName,
1288c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                CFragConnectionID connIDToImport)
1289c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // See comments in interface part.
129079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
1291c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(connIDToImport != nil);
1292c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    return CFMLateImportCore(fragToFixLocator, fragToFixConnID, fragToFixInitRoutine,
1293c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                            weakLinkedLibraryName, FragmentLookup, connIDToImport);
129479e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
129579e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
129679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumstatic pascal OSStatus BundleLookup(ConstStr255Param symName, CFragSymbolClass symClass,
1297c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                        void **symAddr, void *refCon)
1298c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // This is the CFMLateImportLookupProc callback used when
1299c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // late importing from a CFBundle.
130079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
1301c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    OSStatus            err;
1302c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    CFBundleRef bundleToImport;
1303c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    CFStringRef symNameStr;
1304c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1305c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(symName != nil);
1306c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(symAddr != nil);
1307c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(refCon  != nil);
1308c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1309c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    symNameStr = nil;
1310c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1311c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    bundleToImport = (CFBundleRef) refCon;
1312c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1313c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Shame there's no way to validate that bundleToImport is really a bundle.
1314c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1315c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // We can only find function pointers because CFBundleGetFunctionPointerForName
1316c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // only works for function pointers.  So if the client is asking for something
1317c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // other than a function pointer (ie TVector symbol) then we don't even true.
1318c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // Also assert in the debug build because this shows a certain lack of
1319c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // understanding on the part of the client.
1320c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    //
1321c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // CF is being revise to support accessing data symbols using a new API
1322c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // (currently this is available to Apple internal developers as
1323c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // CFBundleGetDataPointerForName).  When the new API is available in a
1324c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // public header file I should revise this code to lift this restriction.
1325c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou
1326c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    err = noErr;
1327c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (symClass != kTVectorCFragSymbol) {
1328c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        MoreAssertQ(false);
1329c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        err = cfragNoSymbolErr;
1330c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
1331c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (err == noErr) {
1332c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        symNameStr = CFStringCreateWithPascalString(kCFAllocatorSystemDefault,
1333c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                                symName, kCFStringEncodingMacRoman);
1334c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if (symNameStr == nil) {
1335c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            err = coreFoundationUnknownErr;
1336c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
1337c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
1338c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (err == noErr) {
1339c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        *symAddr = CFBundleGetFunctionPointerForName(bundleToImport, symNameStr);
1340c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        if (*symAddr == nil) {
1341c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou            err = cfragNoSymbolErr;
1342c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        }
1343c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
1344c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    if (symNameStr != nil) {
1345c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou        CFRelease(symNameStr);
1346c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    }
1347c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    return err;
134879e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
134979e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum
135079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossumextern pascal OSStatus CFMLateImportBundle(const CFragSystem7DiskFlatLocator *fragToFixLocator,
1351c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                CFragConnectionID fragToFixConnID,
1352c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                CFragInitFunction fragToFixInitRoutine,
1353c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                ConstStr255Param weakLinkedLibraryName,
1354c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                                CFBundleRef bundleToImport)
1355c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    // See comments in interface part.
135679e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum{
1357c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    MoreAssertQ(bundleToImport != nil);
1358c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou    return CFMLateImportCore(fragToFixLocator, fragToFixConnID, fragToFixInitRoutine,
1359c83ea137d7e717f764e2f31fc2544f522de7d857Antoine Pitrou                                                                            weakLinkedLibraryName, BundleLookup, bundleToImport);
136079e71f73e7a62c24e82dabdafcc9b3e71042de22Just van Rossum}
1361