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