123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789 |
- /*++
- Copyright (c) 2012 Minoca Corp. All Rights Reserved
- Module Name:
- elf.c
- Abstract:
- This module implements support for handling the ELF file format.
- Author:
- Evan Green 13-Oct-2012
- Environment:
- Any
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "imp.h"
- #include "elf.h"
- #include "elfn.h"
- #include "elfcomm.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the function names here to 32 and 64 bit specific function names,
- // since this file may be compiled twice in the same executable.
- //
- #if defined(WANT_ELF64)
- //
- // Define structure aliases.
- //
- #define ELF_LOADING_IMAGE ELF64_LOADING_IMAGE
- #define _ELF_LOADING_IMAGE _ELF64_LOADING_IMAGE
- #define PELF_LOADING_IMAGE PELF64_LOADING_IMAGE
- //
- // Define function aliases.
- //
- #define ImpElfLoadImportsForImage ImpElf64LoadImportsForImage
- #define ImpElfLoadImport ImpElf64LoadImport
- #define ImpElfGatherExportInformation ImpElf64GatherExportInformation
- #define ImpElfGetDynamicEntry ImpElf64GetDynamicEntry
- #define ImpElfRelocateImage ImpElf64RelocateImage
- #define ImpElfProcessRelocateSection ImpElf64ProcessRelocateSection
- #define ImpElfAdjustJumpSlots ImpElf64AdjustJumpSlots
- #define ImpElfGetSymbolValue ImpElf64GetSymbolValue
- #define ImpElfGetSymbol ImpElf64GetSymbol
- #define ImpElfApplyRelocation ImpElf64ApplyRelocation
- #define ImpElfFreeContext ImpElf64FreeContext
- #else
- //
- // Define structure aliases.
- //
- #define ELF_LOADING_IMAGE ELF32_LOADING_IMAGE
- #define _ELF_LOADING_IMAGE _ELF32_LOADING_IMAGE
- #define PELF_LOADING_IMAGE PELF32_LOADING_IMAGE
- //
- // Define function aliases.
- //
- #define ImpElfLoadImportsForImage ImpElf32LoadImportsForImage
- #define ImpElfLoadImport ImpElf32LoadImport
- #define ImpElfGatherExportInformation ImpElf32GatherExportInformation
- #define ImpElfGetDynamicEntry ImpElf32GetDynamicEntry
- #define ImpElfRelocateImage ImpElf32RelocateImage
- #define ImpElfProcessRelocateSection ImpElf32ProcessRelocateSection
- #define ImpElfAdjustJumpSlots ImpElf32AdjustJumpSlots
- #define ImpElfGetSymbolValue ImpElf32GetSymbolValue
- #define ImpElfGetSymbol ImpElf32GetSymbol
- #define ImpElfApplyRelocation ImpElf32ApplyRelocation
- #define ImpElfFreeContext ImpElf32FreeContext
- #endif
- //
- // Try some magically built-in library paths.
- //
- #define ELF_BUILTIN_LIBRARY_PATH "/lib:/usr/lib:/usr/local/lib"
- //
- // Define an invalid address value for image relocation tracking.
- //
- #define ELF_INVALID_RELOCATION (PVOID)-1
- #define ELF_INVALID_ADDRESS (ELF_ADDR)-1ULL
- //
- // Define the maximum number of program headers before it's just silly.
- //
- #define ELF_MAX_PROGRAM_HEADERS 50
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure stores state variables used while loading an ELF image.
- Members:
- Buffer - Stores the loaded image buffer.
- ElfHeader - Stores a pointer pointing inside the file buffer where the
- main ELF header resides.
- RelocationStart - Stores the lowest address to be modified during image
- relocation.
- RelocationEnd - Stores the address at the end of the highest image
- relocation.
- --*/
- typedef struct _ELF_LOADING_IMAGE {
- IMAGE_BUFFER Buffer;
- PELF_HEADER ElfHeader;
- PVOID RelocationStart;
- PVOID RelocationEnd;
- } ELF_LOADING_IMAGE, *PELF_LOADING_IMAGE;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- ImpElfLoadImportsForImage (
- PLIST_ENTRY ListHead,
- PLOADED_IMAGE Image
- );
- KSTATUS
- ImpElfGatherExportInformation (
- PLOADED_IMAGE Image,
- BOOL UseLoadedAddress
- );
- PELF_DYNAMIC_ENTRY
- ImpElfGetDynamicEntry (
- PLOADED_IMAGE Image,
- ELF_SXWORD Tag
- );
- KSTATUS
- ImpElfRelocateImage (
- PLIST_ENTRY ListHead,
- PLOADED_IMAGE Image
- );
- KSTATUS
- ImpElfProcessRelocateSection (
- PLIST_ENTRY ListHead,
- PLOADED_IMAGE Image,
- PVOID Relocations,
- ELF_XWORD RelocationsSize,
- BOOL Addends
- );
- VOID
- ImpElfAdjustJumpSlots (
- PLOADED_IMAGE Image,
- PVOID Relocations,
- ELF_XWORD RelocationsSize,
- BOOL Addends
- );
- ELF_ADDR
- ImpElfGetSymbolValue (
- PLIST_ENTRY ListHead,
- PLOADED_IMAGE Image,
- PELF_SYMBOL Symbol,
- PLOADED_IMAGE *FoundImage,
- PLOADED_IMAGE SkipImage
- );
- PELF_SYMBOL
- ImpElfGetSymbol (
- PLOADED_IMAGE Image,
- ULONG Hash,
- PSTR SymbolName
- );
- BOOL
- ImpElfApplyRelocation (
- PLIST_ENTRY ListHead,
- PLOADED_IMAGE Image,
- PELF_RELOCATION_ADDEND_ENTRY RelocationEntry,
- BOOL AddendEntry,
- PVOID *FinalSymbolValue
- );
- VOID
- ImpElfFreeContext (
- PLOADED_IMAGE Image
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- ImpElfOpenLibrary (
- PLIST_ENTRY ListHead,
- PLOADED_IMAGE Parent,
- PSTR LibraryName,
- PIMAGE_FILE_INFORMATION File,
- PSTR *Path
- )
- /*++
- Routine Description:
- This routine attempts to open a dynamic library.
- Arguments:
- ListHead - Supplies an optional pointer to the head of the list of loaded
- images.
- Parent - Supplies a pointer to the parent image requiring this image for
- load.
- LibraryName - Supplies the name of the library to open.
- File - Supplies a pointer where the information for the file including its
- open handle will be returned.
- Path - Supplies a pointer where the real path to the opened file will be
- returned. The caller is responsible for freeing this memory.
- Return Value:
- Status code.
- --*/
- {
- PSTR PathList;
- PLOADED_IMAGE PrimaryExecutable;
- ULONG PrimaryLoad;
- PELF_DYNAMIC_ENTRY RPath;
- PLOADED_IMAGE RPathParent;
- PELF_DYNAMIC_ENTRY RunPath;
- PSTR Slash;
- KSTATUS Status;
- //
- // If there's a slash, then just load the library without paths.
- //
- Slash = RtlStringFindCharacter(LibraryName, '/', -1);
- if (Slash != NULL) {
- Status = ImpElfOpenWithPathList(Parent, LibraryName, "", File, Path);
- goto OpenLibraryEnd;
- }
- //
- // First find a DT_RUNPATH. If both DT_RUNPATH and DT_RPATH are found,
- // ignore the older DT_RPATH. DT_RPATH goes up the chain of imports.
- //
- PrimaryLoad = 0;
- RunPath = ImpElfGetDynamicEntry(Parent, ELF_DYNAMIC_RUN_PATH);
- if (RunPath == NULL) {
- RPathParent = Parent;
- while (RPathParent != NULL) {
- PrimaryLoad |= RPathParent->LoadFlags;
- RPath = ImpElfGetDynamicEntry(RPathParent, ELF_DYNAMIC_RPATH);
- if (RPath != NULL) {
- PathList = RPathParent->ExportStringTable + RPath->Value;
- Status = ImpElfOpenWithPathList(Parent,
- LibraryName,
- PathList,
- File,
- Path);
- if (KSUCCESS(Status)) {
- goto OpenLibraryEnd;
- }
- }
- RPathParent = RPathParent->Parent;
- }
- //
- // Try the DT_RPATH of the primary executable if provided and not
- // already searched.
- //
- if ((PrimaryLoad & IMAGE_LOAD_FLAG_PRIMARY_LOAD) == 0) {
- PrimaryExecutable = ImpGetPrimaryExecutable(ListHead);
- if ((PrimaryExecutable != NULL) &&
- (PrimaryExecutable != Parent) &&
- (PrimaryExecutable->DynamicSection != NULL)) {
- RPath = ImpElfGetDynamicEntry(PrimaryExecutable,
- ELF_DYNAMIC_RPATH);
- if (RPath != NULL) {
- PathList = PrimaryExecutable->ExportStringTable +
- RPath->Value;
- Status = ImpElfOpenWithPathList(Parent,
- LibraryName,
- PathList,
- File,
- Path);
- if (KSUCCESS(Status)) {
- goto OpenLibraryEnd;
- }
- }
- }
- }
- }
- //
- // Get the library search path variable and use that.
- //
- PathList = ImpElfGetEnvironmentVariable(IMAGE_LOAD_LIBRARY_PATH_VARIABLE);
- if (PathList != NULL) {
- Status = ImpElfOpenWithPathList(Parent,
- LibraryName,
- PathList,
- File,
- Path);
- if (KSUCCESS(Status)) {
- goto OpenLibraryEnd;
- }
- }
- //
- // Try DT_RUNPATH.
- //
- if (RunPath != NULL) {
- PathList = Parent->ExportStringTable + RunPath->Value;
- Status = ImpElfOpenWithPathList(Parent,
- LibraryName,
- PathList,
- File,
- Path);
- if (KSUCCESS(Status)) {
- goto OpenLibraryEnd;
- }
- }
- //
- // Try some hard coded paths.
- //
- PathList = ELF_BUILTIN_LIBRARY_PATH;
- Status = ImpElfOpenWithPathList(Parent, LibraryName, PathList, File, Path);
- if (KSUCCESS(Status)) {
- goto OpenLibraryEnd;
- }
- OpenLibraryEnd:
- return Status;
- }
- KSTATUS
- ImpElfGetImageSize (
- PLIST_ENTRY ListHead,
- PLOADED_IMAGE Image,
- PIMAGE_BUFFER Buffer,
- PSTR *InterpreterPath
- )
- /*++
- Routine Description:
- This routine determines the size of an ELF executable image. The image size,
- preferred lowest address, and relocatable flag will all be filled in.
- Arguments:
- ListHead - Supplies a pointer to the head of the list of loaded images.
- Image - Supplies a pointer to the image to get the size of.
- Buffer - Supplies a pointer to the loaded image buffer.
- InterpreterPath - Supplies a pointer where the interpreter name will be
- returned if the program is requesting an interpreter.
- Return Value:
- Returns the size of the expanded image in memory on success.
- 0 on failure.
- --*/
- {
- PELF_HEADER ElfHeader;
- PELF_PROGRAM_HEADER FirstProgramHeader;
- ELF_WORD HeaderSize;
- ELF_ADDR HighestVirtualAddress;
- ELF_ADDR ImageSize;
- PSTR InterpreterName;
- ELF_ADDR LowestVirtualAddress;
- PELF_PROGRAM_HEADER ProgramHeader;
- BOOL Result;
- ELF_ADDR SegmentBase;
- ELF_OFF SegmentCount;
- ELF_ADDR SegmentEnd;
- UINTN SegmentIndex;
- KSTATUS Status;
- ImageSize = 0;
- if (InterpreterPath != NULL) {
- *InterpreterPath = NULL;
- }
- Status = STATUS_UNKNOWN_IMAGE_FORMAT;
- //
- // Get the ELF headers.
- //
- Result = ImpElfGetHeader(Buffer, &ElfHeader);
- if (Result == FALSE) {
- goto GetImageSizeEnd;
- }
- SegmentCount = ElfHeader->ProgramHeaderCount;
- if (SegmentCount > ELF_MAX_PROGRAM_HEADERS) {
- goto GetImageSizeEnd;
- }
- FirstProgramHeader = ImpReadBuffer(
- &(Image->File),
- Buffer,
- ElfHeader->ProgramHeaderOffset,
- ElfHeader->ProgramHeaderSize * SegmentCount);
- if (FirstProgramHeader == NULL) {
- goto GetImageSizeEnd;
- }
- if (ElfHeader->ImageType == ELF_IMAGE_SHARED_OBJECT) {
- Image->Flags |= IMAGE_FLAG_RELOCATABLE;
- } else if (ElfHeader->ImageType == ELF_IMAGE_EXECUTABLE) {
- Image->Flags &= ~IMAGE_FLAG_RELOCATABLE;
- } else {
- Status = STATUS_UNKNOWN_IMAGE_FORMAT;
- goto GetImageSizeEnd;
- }
- switch (ElfHeader->Machine) {
- case ELF_MACHINE_ARM:
- Image->Machine = ImageMachineTypeArm32;
- break;
- case ELF_MACHINE_I386:
- Image->Machine = ImageMachineTypeX86;
- break;
- case ELF_MACHINE_X86_64:
- Image->Machine = ImageMachineTypeX64;
- break;
- case ELF_MACHINE_AARCH64:
- Image->Machine = ImageMachineTypeArm64;
- break;
- default:
- Image->Machine = ImageMachineTypeUnknown;
- break;
- }
- Image->EntryPoint = (PVOID)(UINTN)(ElfHeader->EntryPoint);
- //
- // Loop through the program headers once to get the image size and base
- // address.
- //
- LowestVirtualAddress = (ELF_ADDR)-1ULL;
- HighestVirtualAddress = 0;
- for (SegmentIndex = 0; SegmentIndex < SegmentCount; SegmentIndex += 1) {
- ProgramHeader =
- (PELF_PROGRAM_HEADER)(((PUCHAR)FirstProgramHeader) +
- (SegmentIndex * ElfHeader->ProgramHeaderSize));
- //
- // If this image is requesting an interpreter, go load the interpreter
- // instead of this image.
- //
- if ((ProgramHeader->Type == ELF_SEGMENT_TYPE_INTERPRETER) &&
- (ProgramHeader->FileSize != 0) &&
- (InterpreterPath != NULL) &&
- ((Image->LoadFlags & IMAGE_LOAD_FLAG_IGNORE_INTERPRETER) == 0)) {
- ASSERT(Image->ImportDepth == 0);
- HeaderSize = ProgramHeader->FileSize;
- InterpreterName = ImpReadBuffer(&(Image->File),
- Buffer,
- ProgramHeader->Offset,
- HeaderSize);
- if ((InterpreterName == NULL) ||
- (HeaderSize == 0) ||
- (InterpreterName[HeaderSize - 1] != '\0')) {
- Status = STATUS_UNKNOWN_IMAGE_FORMAT;
- goto GetImageSizeEnd;
- }
- *InterpreterPath = InterpreterName;
- }
- //
- // Skip non-loading segments.
- //
- if (ProgramHeader->Type != ELF_SEGMENT_TYPE_LOAD) {
- continue;
- }
- //
- // Determine where in memory this segment would start and end.
- //
- SegmentBase = ProgramHeader->VirtualAddress;
- SegmentEnd = ProgramHeader->VirtualAddress + ProgramHeader->MemorySize;
- //
- // Update the lowest and highest addresses seen so far.
- //
- if (SegmentBase < LowestVirtualAddress) {
- LowestVirtualAddress = SegmentBase;
- }
- if (SegmentEnd > HighestVirtualAddress) {
- HighestVirtualAddress = SegmentEnd;
- }
- }
- if (LowestVirtualAddress >= HighestVirtualAddress) {
- Status = STATUS_UNKNOWN_IMAGE_FORMAT;
- goto GetImageSizeEnd;
- }
- ImageSize = HighestVirtualAddress - LowestVirtualAddress;
- Image->PreferredLowestAddress = (PVOID)(UINTN)LowestVirtualAddress;
- Status = STATUS_SUCCESS;
- GetImageSizeEnd:
- Image->Size = ImageSize;
- return Status;
- }
- KSTATUS
- ImpElfLoadImage (
- PLIST_ENTRY ListHead,
- PLOADED_IMAGE Image,
- PIMAGE_BUFFER Buffer
- )
- /*++
- Routine Description:
- This routine loads an ELF image into its executable form.
- Arguments:
- ListHead - Supplies a pointer to the head of the list of loaded images.
- Image - Supplies a pointer to the loaded image. This must be partially
- filled out. Notable fields that must be filled out by the caller
- include the loaded virtual address and image size. This routine will
- fill out many other fields.
- Buffer - Supplies a pointer to the image buffer.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_FILE_CORRUPT if the file headers were corrupt or unexpected.
- Other errors on failure.
- --*/
- {
- ELF_ADDR BaseDifference;
- PELF_HEADER ElfHeader;
- PELF_PROGRAM_HEADER FirstProgramHeader;
- BOOL ImageInserted;
- ULONG ImportIndex;
- PELF_LOADING_IMAGE LoadingImage;
- BOOL NotifyLoadCalled;
- PIMAGE_SEGMENT PreviousSegment;
- PELF_PROGRAM_HEADER ProgramHeader;
- BOOL Result;
- PIMAGE_SEGMENT Segment;
- ELF_ADDR SegmentBase;
- ELF_HALF SegmentCount;
- ELF_HALF SegmentIndex;
- KSTATUS Status;
- ImageInserted = FALSE;
- NotifyLoadCalled = FALSE;
- SegmentCount = 0;
- LoadingImage = ImAllocateMemory(sizeof(ELF_LOADING_IMAGE),
- IM_ALLOCATION_TAG);
- if (LoadingImage == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto LoadImageEnd;
- }
- Image->ImageContext = LoadingImage;
- RtlZeroMemory(LoadingImage, sizeof(ELF_LOADING_IMAGE));
- RtlCopyMemory(&(LoadingImage->Buffer), Buffer, sizeof(IMAGE_BUFFER));
- //
- // Get the ELF headers.
- //
- Result = ImpElfGetHeader(Buffer, &ElfHeader);
- if (Result == FALSE) {
- Status = STATUS_FILE_CORRUPT;
- goto LoadImageEnd;
- }
- LoadingImage->ElfHeader = ElfHeader;
- SegmentCount = ElfHeader->ProgramHeaderCount;
- FirstProgramHeader = ImpReadBuffer(
- &(Image->File),
- Buffer,
- ElfHeader->ProgramHeaderOffset,
- ElfHeader->ProgramHeaderSize * SegmentCount);
- if (FirstProgramHeader == NULL) {
- Status = STATUS_UNKNOWN_IMAGE_FORMAT;
- goto LoadImageEnd;
- }
- //
- // Reload the ELF header if reading the program headers caused the buffer
- // to change.
- //
- if (Buffer->Data != ElfHeader) {
- Result = ImpElfGetHeader(Buffer, &ElfHeader);
- if (Result == FALSE) {
- Status = STATUS_FILE_CORRUPT;
- goto LoadImageEnd;
- }
- LoadingImage->ElfHeader = ElfHeader;
- }
- //
- // Allocate space for the image segment structures.
- //
- ASSERT(Image->Segments == NULL);
- if (SegmentCount == 0) {
- Status = STATUS_FILE_CORRUPT;
- goto LoadImageEnd;
- }
- Image->SegmentCount = SegmentCount;
- Image->Segments = ImAllocateMemory(SegmentCount * sizeof(IMAGE_SEGMENT),
- IM_ALLOCATION_TAG);
- if (Image->Segments == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto LoadImageEnd;
- }
- RtlZeroMemory(Image->Segments, SegmentCount * sizeof(IMAGE_SEGMENT));
- //
- // Loop through and load all program headers.
- //
- PreviousSegment = NULL;
- BaseDifference = Image->BaseDifference;
- ProgramHeader = FirstProgramHeader;
- for (SegmentIndex = 0; SegmentIndex < SegmentCount; SegmentIndex += 1) {
- Segment = &(Image->Segments[SegmentIndex]);
- //
- // Remember the TLS segment.
- //
- if (ProgramHeader->Type == ELF_SEGMENT_TYPE_TLS) {
- Image->TlsImage = (PVOID)(UINTN)(ProgramHeader->VirtualAddress) +
- BaseDifference;
- Image->TlsImageSize = ProgramHeader->FileSize;
- Image->TlsSize = ProgramHeader->MemorySize;
- Image->TlsAlignment = ProgramHeader->Alignment;
- }
- //
- // Skip non-loading segments.
- //
- if (ProgramHeader->Type != ELF_SEGMENT_TYPE_LOAD) {
- ProgramHeader += 1;
- continue;
- }
- //
- // Determine where in memory this segment will start.
- //
- SegmentBase = ProgramHeader->VirtualAddress;
- //
- // Convert the flags.
- //
- if ((ProgramHeader->Flags & ELF_PROGRAM_HEADER_FLAG_WRITE) != 0) {
- Segment->Flags |= IMAGE_MAP_FLAG_WRITE;
- }
- if ((ProgramHeader->Flags & ELF_PROGRAM_HEADER_FLAG_EXECUTE) != 0) {
- Segment->Flags |= IMAGE_MAP_FLAG_EXECUTE;
- }
- //
- // The mapping is fixed if it's not the first program header or its
- // not an image that can be relocated.
- //
- if ((PreviousSegment != NULL) ||
- ((Image->Flags & IMAGE_FLAG_RELOCATABLE) == 0)) {
- Segment->Flags |= IMAGE_MAP_FLAG_FIXED;
- }
- //
- // Set up and map the segment.
- //
- Segment->VirtualAddress = (PVOID)(UINTN)SegmentBase + BaseDifference;
- Segment->FileSize = ProgramHeader->FileSize;
- Segment->MemorySize = ProgramHeader->MemorySize;
- //
- // The segments should always be in increasing virtual address order.
- //
- if ((PreviousSegment != NULL) &&
- (PreviousSegment->VirtualAddress + PreviousSegment->MemorySize >
- Segment->VirtualAddress)) {
- Status = STATUS_FILE_CORRUPT;
- goto LoadImageEnd;
- }
- Status = ImMapImageSegment(
- Image->AllocatorHandle,
- Image->PreferredLowestAddress + BaseDifference,
- &(Image->File),
- ProgramHeader->Offset,
- Segment,
- PreviousSegment);
- if (!KSUCCESS(Status)) {
- goto LoadImageEnd;
- }
- //
- // If this was the first section to get slapped down and address space
- // wasn't predetermined, update it now.
- //
- if ((PreviousSegment == NULL) &&
- (Image->AllocatorHandle == INVALID_HANDLE)) {
- Image->BaseDifference = Segment->VirtualAddress -
- Image->PreferredLowestAddress;
- Image->LoadedImageBuffer = Segment->VirtualAddress;
- BaseDifference = Image->BaseDifference;
- }
- Segment->Type = ImageSegmentFileSection;
- PreviousSegment = Segment;
- ProgramHeader = (PELF_PROGRAM_HEADER)((PUCHAR)ProgramHeader +
- ElfHeader->ProgramHeaderSize);
- }
- Image->EntryPoint =
- (PVOID)(UINTN)(LoadingImage->ElfHeader->EntryPoint + BaseDifference);
- INSERT_BEFORE(&(Image->ListEntry), ListHead);
- ImageInserted = TRUE;
- Status = ImNotifyImageLoad(Image);
- if (!KSUCCESS(Status)) {
- goto LoadImageEnd;
- }
- NotifyLoadCalled = TRUE;
- //
- // If only loading, don't process the dynamic section.
- //
- if ((Image->LoadFlags & IMAGE_LOAD_FLAG_LOAD_ONLY) != 0) {
- ImpElfFreeContext(Image);
- goto LoadImageEnd;
- }
- //
- // Gather information not in the loaded part of the file needed for
- // resolving exports from this image.
- //
- Status = ImpElfGatherExportInformation(Image, FALSE);
- if (!KSUCCESS(Status)) {
- goto LoadImageEnd;
- }
- //
- // If the import count is non-zero, then this is an import being loaded.
- // Do nothing else, as relocations and imports happen at the base level.
- //
- if (Image->ImportDepth != 0) {
- Status = STATUS_SUCCESS;
- goto LoadImageEnd;
- }
- //
- // Load imports for all images.
- //
- Status = ImpElfLoadAllImports(ListHead);
- if (!KSUCCESS(Status)) {
- goto LoadImageEnd;
- }
- if ((Image->LoadFlags & IMAGE_LOAD_FLAG_NO_RELOCATIONS) == 0) {
- //
- // Loop through the list again and perform the final relocations now
- // that the complete symbol table is built.
- //
- Status = ImpElfRelocateImages(ListHead);
- if (!KSUCCESS(Status)) {
- goto LoadImageEnd;
- }
- }
- Status = STATUS_SUCCESS;
- LoadImageEnd:
- if (!KSUCCESS(Status)) {
- if (Image->ImageContext != NULL) {
- ImFreeMemory(Image->ImageContext);
- Image->ImageContext = NULL;
- }
- if (NotifyLoadCalled != FALSE) {
- //
- // Unload any imports.
- //
- for (ImportIndex = 0;
- ImportIndex < Image->ImportCount;
- ImportIndex += 1) {
- if (Image->Imports[ImportIndex] != NULL) {
- ImImageReleaseReference(Image->Imports[ImportIndex]);
- }
- }
- if (Image->Imports != NULL) {
- ImFreeMemory(Image->Imports);
- }
- ImNotifyImageUnload(Image);
- }
- if (ImageInserted != FALSE) {
- LIST_REMOVE(&(Image->ListEntry));
- }
- if (Image->Segments != NULL) {
- //
- // Unmap all mapped segments.
- //
- for (SegmentIndex = 0;
- SegmentIndex < SegmentCount;
- SegmentIndex += 1) {
- Segment = &(Image->Segments[SegmentIndex]);
- if (Segment->Type != ImageSegmentInvalid) {
- ImUnmapImageSegment(Image->AllocatorHandle, Segment);
- }
- }
- ImFreeMemory(Image->Segments);
- Image->Segments = NULL;
- Image->SegmentCount = 0;
- }
- if (Image->StaticFunctions != NULL) {
- ImFreeMemory(Image->StaticFunctions);
- }
- }
- return Status;
- }
- KSTATUS
- ImpElfAddImage (
- PIMAGE_BUFFER ImageBuffer,
- PLOADED_IMAGE Image
- )
- /*++
- Routine Description:
- This routine adds the accounting structures for an image that has already
- been loaded into memory.
- Arguments:
- ImageBuffer - Supplies a pointer to the loaded image buffer.
- Image - Supplies a pointer to the image to initialize.
- Return Value:
- Status code.
- --*/
- {
- ELF_ADDR BaseDifference;
- PELF_HEADER ElfHeader;
- PELF_PROGRAM_HEADER FirstProgramHeader;
- ELF_ADDR HighestVirtualAddress;
- ELF_ADDR ImageSize;
- UINTN Index;
- PELF_LOADING_IMAGE LoadingImage;
- ELF_ADDR LowestVirtualAddress;
- PELF_PROGRAM_HEADER ProgramHeader;
- ELF_HALF SegmentCount;
- ELF_ADDR SegmentEnd;
- KSTATUS Status;
- ElfHeader = Image->LoadedImageBuffer;
- Image->Size = ImageBuffer->Size;
- LoadingImage = ImAllocateMemory(sizeof(ELF_LOADING_IMAGE),
- IM_ALLOCATION_TAG);
- if (LoadingImage == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AddImageEnd;
- }
- Image->ImageContext = LoadingImage;
- RtlZeroMemory(LoadingImage, sizeof(ELF_LOADING_IMAGE));
- RtlCopyMemory(&(LoadingImage->Buffer), ImageBuffer, sizeof(IMAGE_BUFFER));
- LoadingImage->ElfHeader = ElfHeader;
- if (ElfHeader->ImageType == ELF_IMAGE_SHARED_OBJECT) {
- Image->Flags |= IMAGE_FLAG_RELOCATABLE;
- } else if (ElfHeader->ImageType == ELF_IMAGE_EXECUTABLE) {
- Image->Flags &= ~IMAGE_FLAG_RELOCATABLE;
- } else {
- Status = STATUS_UNKNOWN_IMAGE_FORMAT;
- goto AddImageEnd;
- }
- switch (ElfHeader->Machine) {
- case ELF_MACHINE_ARM:
- Image->Machine = ImageMachineTypeArm32;
- break;
- case ELF_MACHINE_I386:
- Image->Machine = ImageMachineTypeX86;
- break;
- case ELF_MACHINE_X86_64:
- Image->Machine = ImageMachineTypeX64;
- break;
- case ELF_MACHINE_AARCH64:
- Image->Machine = ImageMachineTypeArm64;
- break;
- default:
- Image->Machine = ImageMachineTypeUnknown;
- break;
- }
- SegmentCount = ElfHeader->ProgramHeaderCount;
- FirstProgramHeader = ImpReadBuffer(
- &(Image->File),
- ImageBuffer,
- ElfHeader->ProgramHeaderOffset,
- ElfHeader->ProgramHeaderSize * SegmentCount);
- if (FirstProgramHeader == NULL) {
- Status = STATUS_UNKNOWN_IMAGE_FORMAT;
- goto AddImageEnd;
- }
- //
- // Loop through the program headers.
- //
- LowestVirtualAddress = (ELF_ADDR)-1ULL;
- HighestVirtualAddress = 0;
- ProgramHeader = FirstProgramHeader;
- for (Index = 0; Index < SegmentCount; Index += 1) {
- //
- // Remember the TLS segment.
- //
- if (ProgramHeader->Type == ELF_SEGMENT_TYPE_TLS) {
- Image->TlsImage = (PVOID)(UINTN)(ProgramHeader->VirtualAddress);
- Image->TlsImageSize = ProgramHeader->FileSize;
- Image->TlsSize = ProgramHeader->MemorySize;
- Image->TlsAlignment = ProgramHeader->Alignment;
- } else if (ProgramHeader->Type == ELF_SEGMENT_TYPE_LOAD) {
- if (ProgramHeader->VirtualAddress < LowestVirtualAddress) {
- LowestVirtualAddress = ProgramHeader->VirtualAddress;
- }
- SegmentEnd = ProgramHeader->VirtualAddress +
- ProgramHeader->MemorySize;
- if (SegmentEnd > HighestVirtualAddress) {
- HighestVirtualAddress = SegmentEnd;
- }
- }
- ProgramHeader = (PELF_PROGRAM_HEADER)((PUCHAR)ProgramHeader +
- ElfHeader->ProgramHeaderSize);
- }
- if (LowestVirtualAddress >= HighestVirtualAddress) {
- Status = STATUS_UNKNOWN_IMAGE_FORMAT;
- goto AddImageEnd;
- }
- ImageSize = HighestVirtualAddress - LowestVirtualAddress;
- ASSERT((Image->Size == MAX_UINTN) || (Image->Size == ImageSize));
- Image->Size = ImageSize;
- Image->PreferredLowestAddress = (PVOID)(UINTN)LowestVirtualAddress;
- BaseDifference = Image->LoadedImageBuffer - Image->PreferredLowestAddress;
- Image->BaseDifference = BaseDifference;
- if (Image->TlsImage != NULL) {
- Image->TlsImage += BaseDifference;
- }
- Image->EntryPoint = (PVOID)(UINTN)(ElfHeader->EntryPoint + BaseDifference);
- Status = ImpElfGatherExportInformation(Image, TRUE);
- if (!KSUCCESS(Status)) {
- goto AddImageEnd;
- }
- AddImageEnd:
- if (!KSUCCESS(Status)) {
- if (Image != NULL) {
- if (Image->ImageContext != NULL) {
- ImFreeMemory(Image->ImageContext);
- Image->ImageContext = NULL;
- }
- if (Image->StaticFunctions != NULL) {
- ImFreeMemory(Image->StaticFunctions);
- }
- }
- }
- return Status;
- }
- VOID
- ImpElfUnloadImage (
- PLOADED_IMAGE Image
- )
- /*++
- Routine Description:
- This routine unloads an ELF executable.
- Arguments:
- Image - Supplies a pointer to the loaded image.
- Return Value:
- None.
- --*/
- {
- UINTN ImportIndex;
- UINTN SegmentIndex;
- ASSERT((Image->ImportCount == 0) || (Image->Imports != NULL));
- ImpElfFreeContext(Image);
- //
- // Unload all imports.
- //
- for (ImportIndex = 0; ImportIndex < Image->ImportCount; ImportIndex += 1) {
- ASSERT(Image->Imports[ImportIndex] != NULL);
- ImImageReleaseReference(Image->Imports[ImportIndex]);
- }
- if (Image->Imports != NULL) {
- ImFreeMemory(Image->Imports);
- }
- ASSERT((Image->Segments != NULL) || (Image->SegmentCount == 0));
- for (SegmentIndex = 0;
- SegmentIndex < Image->SegmentCount;
- SegmentIndex += 1) {
- if (Image->Segments[SegmentIndex].Type != ImageSegmentInvalid) {
- ImUnmapImageSegment(Image->AllocatorHandle,
- &(Image->Segments[SegmentIndex]));
- }
- }
- if (Image->Segments != NULL) {
- ImFreeMemory(Image->Segments);
- Image->Segments = NULL;
- }
- if (Image->StaticFunctions != NULL) {
- ImFreeMemory(Image->StaticFunctions);
- Image->StaticFunctions = NULL;
- }
- return;
- }
- BOOL
- ImpElfGetHeader (
- PIMAGE_BUFFER Buffer,
- PELF_HEADER *ElfHeader
- )
- /*++
- Routine Description:
- This routine returns a pointer to the ELF image header given a buffer
- containing the executable image mapped in memory.
- Arguments:
- Buffer - Supplies a pointer to the loaded image buffer.
- ElfHeader - Supplies a pointer where the location of the ELF header will
- be returned.
- Return Value:
- TRUE on success.
- FALSE otherwise.
- --*/
- {
- UCHAR Class;
- PELF_HEADER Header;
- *ElfHeader = NULL;
- Header = ImpReadBuffer(NULL, Buffer, 0, sizeof(ELF_HEADER));
- if (Header == NULL) {
- return FALSE;
- }
- if ((Header->Identification[0] != ELF_MAGIC0) ||
- (Header->Identification[1] != ELF_MAGIC1) ||
- (Header->Identification[2] != ELF_MAGIC2) ||
- (Header->Identification[3] != ELF_MAGIC3)) {
- return FALSE;
- }
- //
- // Check that the 32/64 bitness agrees.
- //
- Class = Header->Identification[ELF_CLASS_OFFSET];
- if (sizeof(ELF_HEADER) == sizeof(ELF64_HEADER)) {
- if (Class != ELF_64BIT) {
- return FALSE;
- }
- } else {
- if (Class != ELF_32BIT) {
- return FALSE;
- }
- }
- //
- // Only little endian images are supported.
- //
- if (Header->Identification[ELF_ENDIANNESS_OFFSET] != ELF_LITTLE_ENDIAN) {
- return FALSE;
- }
- //
- // Ensure that the program header and section header sizes are consistent.
- //
- if ((Header->ProgramHeaderSize != sizeof(ELF_PROGRAM_HEADER)) ||
- (Header->SectionHeaderSize != sizeof(ELF_SECTION_HEADER))) {
- return FALSE;
- }
- *ElfHeader = Header;
- return TRUE;
- }
- BOOL
- ImpElfGetSection (
- PIMAGE_BUFFER Buffer,
- PSTR SectionName,
- PVOID *Section,
- PULONGLONG VirtualAddress,
- PULONG SectionSizeInFile,
- PULONG SectionSizeInMemory
- )
- /*++
- Routine Description:
- This routine gets a pointer to the given section in an ELF image given a
- memory mapped file.
- Arguments:
- Buffer - Supplies a pointer to the image buffer.
- SectionName - Supplies the name of the desired section.
- Section - Supplies a pointer where the pointer to the section will be
- returned.
- VirtualAddress - Supplies a pointer where the virtual address of the section
- will be returned, if applicable.
- SectionSizeInFile - Supplies a pointer where the size of the section as it
- appears in the file will be returned.
- SectionSizeInMemory - Supplies a pointer where the size of the section as it
- appears after being loaded in memory will be returned.
- Return Value:
- TRUE on success.
- FALSE otherwise.
- --*/
- {
- PSTR CurrentSectionName;
- PELF_HEADER ElfHeader;
- BOOL Match;
- BOOL Result;
- PVOID ReturnSection;
- ELF_WORD ReturnSectionFileSize;
- ELF_WORD ReturnSectionMemorySize;
- ELF_ADDR ReturnSectionVirtualAddress;
- PELF_SECTION_HEADER SectionHeader;
- ELF_HALF SectionIndex;
- PSTR StringTable;
- PELF_SECTION_HEADER StringTableHeader;
- ReturnSection = NULL;
- ReturnSectionFileSize = 0;
- ReturnSectionMemorySize = 0;
- ReturnSectionVirtualAddress = (UINTN)NULL;
- if (SectionName == NULL) {
- Result = FALSE;
- goto GetSectionEnd;
- }
- Result = ImpElfGetHeader(Buffer, &ElfHeader);
- if (Result == FALSE) {
- goto GetSectionEnd;
- }
- //
- // Get the beginning of the section array, and then get the string table.
- //
- SectionHeader = ImpReadBuffer(
- NULL,
- Buffer,
- ElfHeader->SectionHeaderOffset,
- sizeof(ELF_SECTION_HEADER) * ElfHeader->SectionHeaderCount);
- if (SectionHeader == NULL) {
- Result = FALSE;
- goto GetSectionEnd;
- }
- StringTableHeader = SectionHeader + ElfHeader->StringSectionIndex;
- StringTable = ImpReadBuffer(NULL,
- Buffer,
- StringTableHeader->Offset,
- StringTableHeader->Size);
- if (StringTable == NULL) {
- Result = FALSE;
- goto GetSectionEnd;
- }
- //
- // Loop through all sections looking for the desired one.
- //
- for (SectionIndex = 0;
- SectionIndex < ElfHeader->SectionHeaderCount;
- SectionIndex += 1) {
- //
- // Skip null sections.
- //
- if (SectionHeader->SectionType == ELF_SECTION_TYPE_NULL) {
- SectionHeader += 1;
- continue;
- }
- if (SectionHeader->NameOffset >= StringTableHeader->Size) {
- Result = FALSE;
- goto GetSectionEnd;
- }
- CurrentSectionName = StringTable + SectionHeader->NameOffset;
- Match = RtlAreStringsEqual(CurrentSectionName, SectionName, -1);
- //
- // If the name matches, return that section. Sections have no relevance
- // on what is loaded into memory, so all sections have a memory size of
- // zero.
- //
- if (Match != FALSE) {
- ReturnSection = ImpReadBuffer(NULL,
- Buffer,
- SectionHeader->Offset,
- SectionHeader->Size);
- if (ReturnSection == NULL) {
- Result = FALSE;
- goto GetSectionEnd;
- }
- ReturnSectionFileSize = SectionHeader->Size;
- ReturnSectionMemorySize = 0;
- ReturnSectionVirtualAddress = SectionHeader->VirtualAddress;
- break;
- }
- SectionHeader += 1;
- }
- GetSectionEnd:
- if (Section != NULL) {
- *Section = ReturnSection;
- }
- if (VirtualAddress != NULL) {
- *VirtualAddress = ReturnSectionVirtualAddress;
- }
- if (SectionSizeInFile != NULL) {
- *SectionSizeInFile = ReturnSectionFileSize;
- }
- if (SectionSizeInMemory != NULL) {
- *SectionSizeInMemory = ReturnSectionMemorySize;
- }
- return Result;
- }
- KSTATUS
- ImpElfLoadAllImports (
- PLIST_ENTRY ListHead
- )
- /*++
- Routine Description:
- This routine loads all import libraries for all images.
- Arguments:
- ListHead - Supplies a pointer to the head of the list of loaded images.
- Return Value:
- Status code.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PLOADED_IMAGE CurrentImage;
- KSTATUS Status;
- //
- // Loop through the list and load imports for each image. This may cause
- // additional images to get added to the end of the list, but traversal of
- // the list won't get corrupted because images never disappear from the
- // list this way.
- //
- CurrentEntry = ListHead->Next;
- while (CurrentEntry != ListHead) {
- CurrentImage = LIST_VALUE(CurrentEntry, LOADED_IMAGE, ListEntry);
- ASSERT((CurrentImage->LoadFlags & IMAGE_LOAD_FLAG_LOAD_ONLY) == 0);
- if ((CurrentImage->Flags & IMAGE_FLAG_IMPORTS_LOADED) == 0) {
- Status = ImpElfLoadImportsForImage(ListHead, CurrentImage);
- if (!KSUCCESS(Status)) {
- goto LoadAllImportsEnd;
- }
- CurrentImage->Flags |= IMAGE_FLAG_IMPORTS_LOADED;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- Status = STATUS_SUCCESS;
- LoadAllImportsEnd:
- return Status;
- }
- KSTATUS
- ImpElfRelocateImages (
- PLIST_ENTRY ListHead
- )
- /*++
- Routine Description:
- This routine relocates all images on the given image list that have not
- yet been relocated.
- Arguments:
- ListHead - Supplies a pointer to the head of the list to relocate.
- Return Value:
- Status code.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PLOADED_IMAGE CurrentImage;
- KSTATUS Status;
- Status = ImpElfLoadAllImports(ListHead);
- if (!KSUCCESS(Status)) {
- goto RelocateImagesEnd;
- }
- CurrentEntry = ListHead->Previous;
- while (CurrentEntry != ListHead) {
- CurrentImage = LIST_VALUE(CurrentEntry, LOADED_IMAGE, ListEntry);
- if ((CurrentImage->Flags & IMAGE_FLAG_RELOCATED) == 0) {
- Status = ImpElfRelocateImage(ListHead, CurrentImage);
- if (!KSUCCESS(Status)) {
- goto RelocateImagesEnd;
- }
- CurrentImage->Flags |= IMAGE_FLAG_RELOCATED;
- if (ImFinalizeSegments != NULL) {
- Status = ImFinalizeSegments(CurrentImage->AllocatorHandle,
- CurrentImage->Segments,
- CurrentImage->SegmentCount);
- if (!KSUCCESS(Status)) {
- goto RelocateImagesEnd;
- }
- }
- ImpElfFreeContext(CurrentImage);
- }
- CurrentEntry = CurrentEntry->Previous;
- }
- Status = STATUS_SUCCESS;
- RelocateImagesEnd:
- return Status;
- }
- VOID
- ImpElfRelocateSelf (
- PIMAGE_BUFFER Buffer,
- PLOADED_IMAGE Image
- )
- /*++
- Routine Description:
- This routine relocates the currently running image.
- Arguments:
- Buffer - Supplies a pointer to the image buffer.
- Image - Supplies a pointer to the zeroed but otherwise uninitialized
- image buffer.
- Return Value:
- None.
- --*/
- {
- LIST_ENTRY FakeList;
- PSTR InterpreterPath;
- ELF_LOADING_IMAGE LoadingImage;
- KSTATUS Status;
- //
- // Create a fake image list, and a fake ELF loading image context.
- //
- INITIALIZE_LIST_HEAD(&FakeList);
- RtlZeroMemory(&LoadingImage, sizeof(ELF_LOADING_IMAGE));
- RtlCopyMemory(&(LoadingImage.Buffer), Buffer, sizeof(IMAGE_BUFFER));
- //
- // Set the "no static constructors" flag so that gather export information
- // doesn't try to allocate a static functions structure.
- //
- Image->LoadFlags = IMAGE_LOAD_FLAG_PRIMARY_EXECUTABLE |
- IMAGE_LOAD_FLAG_NO_STATIC_CONSTRUCTORS |
- IMAGE_LOAD_FLAG_IGNORE_INTERPRETER;
- Status = ImpElfGetImageSize(&FakeList, Image, Buffer, &InterpreterPath);
- if (!KSUCCESS(Status)) {
- goto ElfRelocateSelfEnd;
- }
- Image->File.Size = Image->Size;
- LoadingImage.Buffer.Size = Image->Size;
- LoadingImage.ElfHeader = Buffer->Data;
- Image->BaseDifference = Buffer->Data - Image->PreferredLowestAddress;
- Image->LoadedImageBuffer = Buffer->Data;
- Image->ImageContext = &LoadingImage;
- Status = ImpElfGatherExportInformation(Image, TRUE);
- if (!KSUCCESS(Status)) {
- goto ElfRelocateSelfEnd;
- }
- Status = ImpElfRelocateImage(&FakeList, Image);
- ElfRelocateSelfEnd:
- Image->ImageContext = NULL;
- ASSERT(KSUCCESS(Status));
- return;
- }
- KSTATUS
- ImpElfGetSymbolByName (
- PLOADED_IMAGE Image,
- PSTR SymbolName,
- PIMAGE_SYMBOL Symbol
- )
- /*++
- Routine Description:
- This routine attempts to find an exported symbol with the given name in the
- given binary.
- Arguments:
- Image - Supplies a pointer to the image to query.
- SymbolName - Supplies a pointer to the string containing the name of the
- symbol to search for.
- Symbol - Supplies a pointer to a structure that receives the symbol's
- information on success.
- Return Value:
- Status code.
- --*/
- {
- PELF_SYMBOL ElfSymbol;
- ULONG Hash;
- ELF_SYMBOL_TYPE SymbolType;
- ELF_ADDR Value;
- if ((Image->Flags & IMAGE_FLAG_GNU_HASH) != 0) {
- Hash = ImpElfGnuHash(SymbolName);
- } else {
- Hash = ImpElfOriginalHash(SymbolName);
- }
- ElfSymbol = ImpElfGetSymbol(Image, Hash, SymbolName);
- if ((ElfSymbol == NULL) || (ElfSymbol->SectionIndex == 0)) {
- return STATUS_NOT_FOUND;
- }
- //
- // TLS symbols are relative to their section base and are not adjusted.
- //
- Symbol->TlsAddress = FALSE;
- SymbolType = ELF_GET_SYMBOL_TYPE(ElfSymbol->Information);
- if (SymbolType == ElfSymbolTls) {
- Value = ElfSymbol->Value;
- Symbol->TlsAddress = TRUE;
- } else if (ElfSymbol->SectionIndex >= ELF_SECTION_RESERVED_LOW) {
- if (ElfSymbol->SectionIndex != ELF_SECTION_ABSOLUTE) {
- return STATUS_NOT_FOUND;
- }
- Value = ElfSymbol->Value;
- } else {
- Value = ElfSymbol->Value + Image->BaseDifference;
- }
- Symbol->Address = (PVOID)(UINTN)Value;
- Symbol->Name = Image->ExportStringTable + ElfSymbol->NameOffset;
- Symbol->Image = Image;
- return STATUS_SUCCESS;
- }
- KSTATUS
- ImpElfGetSymbolByAddress (
- PLOADED_IMAGE Image,
- PVOID Address,
- PIMAGE_SYMBOL Symbol
- )
- /*++
- Routine Description:
- This routine attempts to find the given address in the given image and
- resolve it to a symbol.
- Arguments:
- Image - Supplies a pointer to the image to query.
- Address - Supplies the address to search for.
- Symbol - Supplies a pointer to a structure that receives the address's
- symbol information on success.
- Return Value:
- Status code.
- --*/
- {
- ELF_ADDR BaseDifference;
- ELF_WORD BucketCount;
- ELF_WORD BucketIndex;
- PELF_SYMBOL ElfSymbol;
- ELF_WORD FilterWords;
- PELF_WORD HashBuckets;
- PELF_WORD HashChains;
- PELF_WORD HashTable;
- PVOID LoadedLowestAddress;
- ELF_ADDR SymbolAddress;
- ELF_WORD SymbolBase;
- ULONG SymbolHash;
- ELF_WORD SymbolIndex;
- PSTR SymbolName;
- ELF_ADDR Value;
- //
- // If the address is not within the bounds of the image, then it should not
- // be in the symbols.
- //
- BaseDifference = Image->BaseDifference;
- LoadedLowestAddress = Image->PreferredLowestAddress + BaseDifference;
- if ((Address < LoadedLowestAddress) ||
- (Address >= (LoadedLowestAddress + Image->Size))) {
- return STATUS_NOT_FOUND;
- }
- SymbolName = NULL;
- SymbolAddress = 0;
- //
- // If there is no export symbol table for this image, then only report the
- // image binary name and address without symbol information.
- //
- if (Image->ExportSymbolTable == NULL) {
- goto GetAddressInformationEnd;
- }
- //
- // Search for the symbol by its value, which is an address relative to the
- // preferred lowest address.
- //
- Value = (ELF_ADDR)(UINTN)Address - BaseDifference;
- //
- // Handle GNU-style hashing to interate over the symbols.
- //
- if ((Image->Flags & IMAGE_FLAG_GNU_HASH) != 0) {
- HashTable = Image->ExportHashTable;
- BucketCount = *HashTable;
- HashTable += 1;
- SymbolBase = *HashTable;
- HashTable += 1;
- FilterWords = *HashTable;
- HashTable += 2;
- HashTable = (PELF_WORD)(HashTable + FilterWords);
- for (BucketIndex = 0; BucketIndex < BucketCount; BucketIndex += 1) {
- SymbolIndex = HashTable[BucketIndex];
- if (SymbolIndex == 0) {
- break;
- }
- if (SymbolIndex < SymbolBase) {
- ASSERT(FALSE);
- break;
- }
- HashChains = HashTable + BucketCount;
- do {
- SymbolHash = HashChains[SymbolIndex - SymbolBase];
- ElfSymbol = (PELF_SYMBOL)Image->ExportSymbolTable + SymbolIndex;
- if (((ElfSymbol->Size == 0) && (ElfSymbol->Value == Value)) ||
- ((Value >= ElfSymbol->Value) &&
- (Value < (ElfSymbol->Value + ElfSymbol->Size)))) {
- SymbolName = Image->ExportStringTable +
- ElfSymbol->NameOffset;
- SymbolAddress = ElfSymbol->Value + BaseDifference;
- goto GetAddressInformationEnd;
- }
- SymbolIndex += 1;
- } while ((SymbolHash & 0x1) == 0);
- }
- //
- // Handle SVR hashing's mode of storing symbols.
- //
- } else {
- BucketCount = *((PELF_WORD)Image->ExportHashTable);
- HashBuckets = (PELF_WORD)Image->ExportHashTable + 2;
- HashChains = (PELF_WORD)Image->ExportHashTable + 2 + BucketCount;
- for (BucketIndex = 0; BucketIndex < BucketCount; BucketIndex += 1) {
- SymbolIndex = *(HashBuckets + BucketIndex);
- while (SymbolIndex != 0) {
- ElfSymbol = (PELF_SYMBOL)Image->ExportSymbolTable + SymbolIndex;
- if (((ElfSymbol->Size == 0) && (ElfSymbol->Value == Value)) ||
- ((Value >= ElfSymbol->Value) &&
- (Value < (ElfSymbol->Value + ElfSymbol->Size)))) {
- SymbolName = Image->ExportStringTable +
- ElfSymbol->NameOffset;
- SymbolAddress = ElfSymbol->Value + BaseDifference;
- goto GetAddressInformationEnd;
- }
- //
- // Get the next entry in the chain.
- //
- SymbolIndex = *(HashChains + SymbolIndex);
- }
- }
- }
- GetAddressInformationEnd:
- Symbol->Image = Image;
- Symbol->Name = SymbolName;
- Symbol->Address = (PVOID)(UINTN)SymbolAddress;
- Symbol->TlsAddress = FALSE;
- return STATUS_SUCCESS;
- }
- PVOID
- ImpElfResolvePltEntry (
- PLIST_ENTRY ListHead,
- PLOADED_IMAGE Image,
- UINTN RelocationOffset
- )
- /*++
- Routine Description:
- This routine implements the slow path for a Procedure Linkable Table entry
- that has not yet been resolved to its target function address. This routine
- is only called once for each PLT entry, as subsequent calls jump directly
- to the destination function address. It resolves the appropriate GOT
- relocation and returns a pointer to the function to jump to.
- Arguments:
- ListHead - Supplies a pointer to the head of the list of images to use for
- symbol resolution.
- Image - Supplies a pointer to the loaded image whose PLT needs resolution.
- This is really whatever pointer is in GOT + 4.
- RelocationOffset - Supplies the byte offset from the start of the
- relocation section where the relocation for this PLT entry resides, or
- the PLT index, depending on the architecture.
- Return Value:
- Returns a pointer to the function to jump to (in addition to writing that
- address in the GOT at the appropriate spot).
- --*/
- {
- PVOID FunctionAddress;
- PVOID RelocationEntry;
- UINTN RelocationSize;
- BOOL Result;
- FunctionAddress = NULL;
- //
- // On ARM, what's passed in is a PLT index. Convert that to an offset based
- // on the size of each PLT entry.
- //
- if (Image->Machine == ImageMachineTypeArm32) {
- RelocationSize = sizeof(ELF32_RELOCATION_ENTRY);
- if (Image->PltRelocationsAddends != FALSE) {
- RelocationSize = sizeof(ELF32_RELOCATION_ADDEND_ENTRY);
- }
- RelocationOffset *= RelocationSize;
- }
- RelocationEntry = Image->PltRelocations + RelocationOffset;
- Result = ImpElfApplyRelocation(ListHead,
- Image,
- RelocationEntry,
- Image->PltRelocationsAddends,
- &FunctionAddress);
- ASSERT(Result != FALSE);
- return FunctionAddress;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- ImpElfLoadImportsForImage (
- PLIST_ENTRY ListHead,
- PLOADED_IMAGE Image
- )
- /*++
- Routine Description:
- This routine loads all import libraries for the given image. It does not
- perform relocations or load imports of the imports.
- Arguments:
- ListHead - Supplies a pointer to the head of the list of loaded images.
- Image - Supplies a pointer to the loaded image structure.
- Return Value:
- Status code.
- --*/
- {
- PELF_DYNAMIC_ENTRY DynamicEntry;
- PLOADED_IMAGE Import;
- ULONG ImportCount;
- ULONG ImportIndex;
- PSTR ImportName;
- ULONG LoadFlags;
- PELF_LOADING_IMAGE LoadingImage;
- KSTATUS Status;
- ELF_OFF StringTableOffset;
- LoadingImage = Image->ImageContext;
- ASSERT(LoadingImage != NULL);
- DynamicEntry = Image->DynamicSection;
- Status = STATUS_SUCCESS;
- if (DynamicEntry == NULL) {
- goto LoadImportsForImageEnd;
- }
- //
- // Loop over all dynamic entries once to count the number of import
- // libraries needed.
- //
- ImportCount = 0;
- while (DynamicEntry->Tag != ELF_DYNAMIC_NULL) {
- //
- // A "needed" entry indicates a required import library.
- //
- if (DynamicEntry->Tag == ELF_DYNAMIC_NEEDED) {
- ImportCount += 1;
- }
- DynamicEntry += 1;
- }
- if (ImportCount == 0) {
- Status = STATUS_SUCCESS;
- goto LoadImportsForImageEnd;
- }
- //
- // Allocate space to hold the imports.
- //
- ASSERT(Image->Imports == NULL);
- Image->Imports = ImAllocateMemory(ImportCount * sizeof(PLOADED_IMAGE),
- IM_ALLOCATION_TAG);
- if (Image->Imports == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto LoadImportsForImageEnd;
- }
- RtlZeroMemory(Image->Imports, ImportCount * sizeof(PLOADED_IMAGE));
- Image->ImportCount = ImportCount;
- ImportIndex = 0;
- DynamicEntry = Image->DynamicSection;
- while (DynamicEntry->Tag != ELF_DYNAMIC_NULL) {
- //
- // A "needed" entry indicates a required import library.
- //
- if (DynamicEntry->Tag == ELF_DYNAMIC_NEEDED) {
- StringTableOffset = DynamicEntry->Value;
- ASSERT((Image->ExportStringTable != NULL) &&
- (StringTableOffset < Image->ExportStringTableSize));
- ImportName = (PSTR)Image->ExportStringTable + StringTableOffset;
- //
- // Load the import. Dynamic libraries shouldn't have interpreters
- // specified.
- //
- LoadFlags = Image->LoadFlags | IMAGE_LOAD_FLAG_IGNORE_INTERPRETER;
- LoadFlags &= ~IMAGE_LOAD_FLAG_PRIMARY_EXECUTABLE;
- Status = ImpLoad(ListHead,
- ImportName,
- NULL,
- NULL,
- Image->SystemContext,
- LoadFlags,
- Image,
- &Import,
- NULL);
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("%s: Failed to find import '%s'.\n",
- Image->FileName,
- ImportName);
- goto LoadImportsForImageEnd;
- }
- Image->Imports[ImportIndex] = Import;
- ImportIndex += 1;
- }
- DynamicEntry += 1;
- }
- LoadImportsForImageEnd:
- if (!KSUCCESS(Status)) {
- if (Image->Imports != NULL) {
- if (ImportIndex != 0) {
- ImportCount = ImportIndex - 1;
- for (ImportIndex = 0;
- ImportIndex < ImportCount;
- ImportIndex += 1) {
- ImImageReleaseReference(Image->Imports[ImportIndex]);
- }
- }
- ImFreeMemory(Image->Imports);
- Image->Imports = NULL;
- Image->ImportCount = 0;
- }
- }
- return Status;
- }
- KSTATUS
- ImpElfGatherExportInformation (
- PLOADED_IMAGE Image,
- BOOL UseLoadedAddress
- )
- /*++
- Routine Description:
- This routine gathers necessary pointers from the non-loaded portion of the
- image file needed to retrieve exports from the image.
- Arguments:
- Image - Supplies a pointer to the loaded image.
- UseLoadedAddress - Supplies a boolean indicating whether to use the file
- offset (FALSE) or the final virtual address (TRUE).
- Return Value:
- Status code.
- --*/
- {
- PVOID Address;
- ELF_ADDR BaseDifference;
- PELF_DYNAMIC_ENTRY DynamicEntry;
- PVOID DynamicSymbols;
- PVOID DynamicSymbolStrings;
- ELF_XWORD DynamicSymbolStringsSize;
- PELF_ADDR Got;
- PELF_WORD HashTable;
- ELF_XWORD HashTag;
- ELF_HALF HeaderCount;
- ELF_HALF Index;
- ELF_XWORD LibraryNameOffset;
- PELF_LOADING_IMAGE LoadingImage;
- PVOID PltRelocations;
- BOOL PltRelocationsAddends;
- PELF_PROGRAM_HEADER ProgramHeader;
- PIMAGE_STATIC_FUNCTIONS StaticFunctions;
- KSTATUS Status;
- ELF_SXWORD Tag;
- ELF_XWORD Value;
- DynamicSymbols = NULL;
- DynamicSymbolStrings = NULL;
- DynamicSymbolStringsSize = 0;
- HashTable = NULL;
- HashTag = 0;
- LibraryNameOffset = 0;
- LoadingImage = Image->ImageContext;
- HeaderCount = LoadingImage->ElfHeader->ProgramHeaderCount;
- PltRelocations = NULL;
- PltRelocationsAddends = FALSE;
- ProgramHeader = NULL;
- StaticFunctions = NULL;
- //
- // This function is not using the read buffer functions because it should
- // only be called in the actual runtime address space, in which case the
- // image is fully loaded.
- //
- ASSERT(LoadingImage->Buffer.Size == Image->File.Size);
- //
- // Loop through the program headers to find the dynamic section.
- //
- for (Index = 0; Index < HeaderCount; Index += 1) {
- ProgramHeader = LoadingImage->Buffer.Data +
- LoadingImage->ElfHeader->ProgramHeaderOffset +
- (Index * LoadingImage->ElfHeader->ProgramHeaderSize);
- if (ProgramHeader->Type == ELF_SEGMENT_TYPE_DYNAMIC) {
- break;
- }
- }
- if (Index == LoadingImage->ElfHeader->ProgramHeaderCount) {
- Status = STATUS_SUCCESS;
- goto GatherExportInformationEnd;
- }
- //
- // Allocate the static functions structure if needed.
- //
- StaticFunctions = Image->StaticFunctions;
- if ((StaticFunctions == NULL) &&
- ((Image->LoadFlags & IMAGE_LOAD_FLAG_NO_STATIC_CONSTRUCTORS) == 0)) {
- StaticFunctions = ImAllocateMemory(sizeof(IMAGE_STATIC_FUNCTIONS),
- IM_ALLOCATION_TAG);
- if (StaticFunctions == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto GatherExportInformationEnd;
- }
- RtlZeroMemory(StaticFunctions, sizeof(IMAGE_STATIC_FUNCTIONS));
- Image->StaticFunctions = StaticFunctions;
- }
- BaseDifference = Image->BaseDifference;
- //
- // If the loaded image buffer address is the loaded address, then go ahead
- // and indicate things are live.
- //
- if (Image->PreferredLowestAddress + BaseDifference ==
- Image->LoadedImageBuffer) {
- UseLoadedAddress = TRUE;
- }
- if (UseLoadedAddress != FALSE) {
- BaseDifference = Image->BaseDifference;
- DynamicEntry = (PVOID)(UINTN)(ProgramHeader->VirtualAddress +
- BaseDifference);
- } else {
- BaseDifference = Image->LoadedImageBuffer -
- Image->PreferredLowestAddress;
- DynamicEntry = LoadingImage->Buffer.Data + ProgramHeader->Offset;
- }
- //
- // Save the pointer to the dynamic section header and dynamic symbol count.
- // This is used by the load import routine.
- //
- Image->DynamicSection = DynamicEntry;
- while (DynamicEntry->Tag != ELF_DYNAMIC_NULL) {
- Tag = DynamicEntry->Tag;
- Value = DynamicEntry->Value;
- Address = (PVOID)(UINTN)(Value + BaseDifference);
- switch (Tag) {
- case ELF_DYNAMIC_LIBRARY_NAME:
- LibraryNameOffset = Value;
- break;
- //
- // Remember the string table.
- //
- case ELF_DYNAMIC_STRING_TABLE:
- DynamicSymbolStrings = Address;
- break;
- //
- // Remember the string table size.
- //
- case ELF_DYNAMIC_STRING_TABLE_SIZE:
- DynamicSymbolStringsSize = Value;
- break;
- //
- // Remember the symbol table.
- //
- case ELF_DYNAMIC_SYMBOL_TABLE:
- DynamicSymbols = Address;
- break;
- //
- // Remember the hash table.
- //
- case ELF_DYNAMIC_HASH_TABLE:
- case ELF_DYNAMIC_GNU_HASH_TABLE:
- HashTable = Address;
- HashTag = Tag;
- break;
- //
- // Remember static constructor and destructor array boundaries, and the
- // old _init and _fini functions.
- //
- case ELF_DYNAMIC_PREINIT_ARRAY:
- if (StaticFunctions != NULL) {
- StaticFunctions->PreinitArray = Address;
- }
- break;
- case ELF_DYNAMIC_INIT_ARRAY:
- if (StaticFunctions != NULL) {
- StaticFunctions->InitArray = Address;
- }
- break;
- case ELF_DYNAMIC_FINI_ARRAY:
- if (StaticFunctions != NULL) {
- StaticFunctions->FiniArray = Address;
- }
- break;
- case ELF_DYNAMIC_INIT:
- if (StaticFunctions != NULL) {
- StaticFunctions->InitFunction = Address;
- }
- break;
- case ELF_DYNAMIC_FINI:
- if (StaticFunctions != NULL) {
- StaticFunctions->FiniFunction = Address;
- }
- break;
- case ELF_DYNAMIC_PREINIT_ARRAY_SIZE:
- if (StaticFunctions != NULL) {
- StaticFunctions->PreinitArraySize = Value;
- }
- break;
- case ELF_DYNAMIC_INIT_ARRAY_SIZE:
- if (StaticFunctions != NULL) {
- StaticFunctions->InitArraySize = Value;
- }
- break;
- case ELF_DYNAMIC_FINI_ARRAY_SIZE:
- if (StaticFunctions != NULL) {
- StaticFunctions->FiniArraySize = Value;
- }
- break;
- case ELF_DYNAMIC_FLAGS:
- if ((Value & ELF_DYNAMIC_FLAG_STATIC_TLS) != 0) {
- Image->Flags |= IMAGE_FLAG_STATIC_TLS;
- //
- // Images with a static TLS model cannot be loaded dynamically,
- // the must be loaded with the initial executable.
- //
- if ((Image->LoadFlags & IMAGE_LOAD_FLAG_PRIMARY_LOAD) == 0) {
- Status = STATUS_TOO_LATE;
- goto GatherExportInformationEnd;
- }
- }
- break;
- //
- // Upon finding the GOT, save the image and the resolution address in
- // the second and third entries of the GOT. Note that reaching through
- // a global would be bad if trying to relocate oneself, but that
- // should only ever be done by the dynamic linker, which won't have
- // imports.
- //
- case ELF_DYNAMIC_PLT_GOT:
- Got = Address;
- Got[1] = (UINTN)Image;
- Got[2] = (UINTN)(ImImportTable->ResolvePltEntry);
- break;
- //
- // Remember where the Procedure Linkage Table relocations are for
- // lazy binding.
- //
- case ELF_DYNAMIC_JUMP_RELOCATIONS:
- PltRelocations = Address;
- break;
- case ELF_DYNAMIC_PLT_RELOCATION_TYPE:
- if (DynamicEntry->Value == ELF_DYNAMIC_RELA_TABLE) {
- PltRelocationsAddends = TRUE;
- }
- break;
- case ELF_DYNAMIC_TEXT_RELOCATIONS:
- Image->Flags |= IMAGE_FLAG_TEXT_RELOCATIONS;
- break;
- //
- // Stick a pointer to the debug structure into the debug dynamic entry.
- // Don't do this if loading from some alternate address space.
- //
- case ELF_DYNAMIC_DEBUG:
- if (UseLoadedAddress != FALSE) {
- DynamicEntry->Value = (ELF_SWORD)&(Image->Debug);
- }
- break;
- case ELF_DYNAMIC_BIND_NOW:
- Image->LoadFlags |= IMAGE_LOAD_FLAG_BIND_NOW;
- break;
- default:
- break;
- }
- DynamicEntry += 1;
- }
- //
- // If one of the required elements was not found, then as far as this
- // library is concerned there is no export information.
- //
- if ((DynamicSymbols == NULL) || (DynamicSymbolStrings == NULL) ||
- (DynamicSymbolStringsSize == 0) || (HashTable == NULL)) {
- Status = STATUS_SUCCESS;
- goto GatherExportInformationEnd;
- }
- Image->ExportSymbolTable = DynamicSymbols;
- Image->ExportStringTable = DynamicSymbolStrings;
- Image->ExportStringTableSize = DynamicSymbolStringsSize;
- Image->ExportHashTable = HashTable;
- Image->PltRelocations = PltRelocations;
- Image->PltRelocationsAddends = PltRelocationsAddends;
- if (HashTag == ELF_DYNAMIC_GNU_HASH_TABLE) {
- Image->Flags |= IMAGE_FLAG_GNU_HASH;
- }
- //
- // Set the library name if there is one.
- //
- if (LibraryNameOffset != 0) {
- Image->LibraryName = DynamicSymbolStrings + LibraryNameOffset;
- }
- Status = STATUS_SUCCESS;
- GatherExportInformationEnd:
- return Status;
- }
- PELF_DYNAMIC_ENTRY
- ImpElfGetDynamicEntry (
- PLOADED_IMAGE Image,
- ELF_SXWORD Tag
- )
- /*++
- Routine Description:
- This routine attempts to find a dynamic entry with the given tag.
- Arguments:
- Image - Supplies a pointer to the image.
- Tag - Supplies the desired tag.
- Return Value:
- Returns a pointer to the requested entry on success.
- NULL if the entry could not be found or there is no dynamic section.
- --*/
- {
- PELF_DYNAMIC_ENTRY Entry;
- Entry = Image->DynamicSection;
- if (Entry != NULL) {
- while (Entry->Tag != ELF_DYNAMIC_NULL) {
- if (Entry->Tag == Tag) {
- return Entry;
- }
- Entry += 1;
- }
- }
- return NULL;
- }
- KSTATUS
- ImpElfRelocateImage (
- PLIST_ENTRY ListHead,
- PLOADED_IMAGE Image
- )
- /*++
- Routine Description:
- This routine relocates a loaded image.
- Arguments:
- ListHead - Supplies a pointer to the head of the list of loaded images.
- Image - Supplies a pointer to the loaded image.
- Return Value:
- Status code.
- --*/
- {
- PVOID Address;
- ELF_ADDR BaseDifference;
- PELF_DYNAMIC_ENTRY DynamicEntry;
- PELF_LOADING_IMAGE LoadingImage;
- BOOL PltRelocationAddends;
- PVOID PltRelocations;
- ELF_XWORD PltRelocationsSize;
- PVOID Relocations;
- PVOID RelocationsAddends;
- ELF_XWORD RelocationsAddendsSize;
- ELF_XWORD RelocationsSize;
- UINTN Size;
- KSTATUS Status;
- LoadingImage = Image->ImageContext;
- ASSERT(LoadingImage != NULL);
- ASSERT((Image->LoadFlags & IMAGE_LOAD_FLAG_PLACEHOLDER) == 0);
- PltRelocationAddends = FALSE;
- PltRelocations = NULL;
- PltRelocationsSize = 0;
- Relocations = NULL;
- RelocationsAddends = NULL;
- RelocationsSize = 0;
- RelocationsAddendsSize = 0;
- LoadingImage->RelocationStart = ELF_INVALID_RELOCATION;
- LoadingImage->RelocationEnd = ELF_INVALID_RELOCATION;
- BaseDifference = (UINTN)(Image->LoadedImageBuffer -
- Image->PreferredLowestAddress);
- DynamicEntry = Image->DynamicSection;
- if (DynamicEntry == NULL) {
- Status = STATUS_SUCCESS;
- goto RelocateImageEnd;
- }
- while (DynamicEntry->Tag != ELF_DYNAMIC_NULL) {
- Address = (PVOID)(UINTN)(DynamicEntry->Value + BaseDifference);
- switch (DynamicEntry->Tag) {
- case ELF_DYNAMIC_REL_TABLE:
- Relocations = Address;
- break;
- case ELF_DYNAMIC_REL_TABLE_SIZE:
- RelocationsSize = DynamicEntry->Value;
- break;
- case ELF_DYNAMIC_RELA_TABLE:
- RelocationsAddends = Address;
- break;
- case ELF_DYNAMIC_RELA_TABLE_SIZE:
- RelocationsAddendsSize = DynamicEntry->Value;
- break;
- case ELF_DYNAMIC_JUMP_RELOCATIONS:
- PltRelocations = Address;
- break;
- case ELF_DYNAMIC_PLT_REL_SIZE:
- PltRelocationsSize = DynamicEntry->Value;
- break;
- case ELF_DYNAMIC_PLT_RELOCATION_TYPE:
- if (DynamicEntry->Value == ELF_DYNAMIC_RELA_TABLE) {
- PltRelocationAddends = TRUE;
- }
- break;
- default:
- break;
- }
- DynamicEntry += 1;
- }
- if ((Relocations != NULL) && (RelocationsSize != 0)) {
- Status = ImpElfProcessRelocateSection(ListHead,
- Image,
- Relocations,
- RelocationsSize,
- FALSE);
- if (!KSUCCESS(Status)) {
- goto RelocateImageEnd;
- }
- }
- if ((RelocationsAddends != NULL) && (RelocationsAddendsSize != 0)) {
- Status = ImpElfProcessRelocateSection(ListHead,
- Image,
- RelocationsAddends,
- RelocationsAddendsSize,
- TRUE);
- if (!KSUCCESS(Status)) {
- goto RelocateImageEnd;
- }
- }
- //
- // Only process the PLT relocations now if lazy binding is disabled.
- // Otherwise, these relocations get patched up when they're called, but
- // need to be adjusted by the base difference. This is much faster as
- // symbol lookups don't need to be done.
- //
- if ((PltRelocations != NULL) && (PltRelocationsSize != 0)) {
- if ((Image->LoadFlags & IMAGE_LOAD_FLAG_BIND_NOW) != 0) {
- Status = ImpElfProcessRelocateSection(ListHead,
- Image,
- PltRelocations,
- PltRelocationsSize,
- PltRelocationAddends);
- if (!KSUCCESS(Status)) {
- goto RelocateImageEnd;
- }
- } else {
- ImpElfAdjustJumpSlots(Image,
- PltRelocations,
- PltRelocationsSize,
- PltRelocationAddends);
- }
- }
- Status = STATUS_SUCCESS;
- RelocateImageEnd:
- if (LoadingImage->RelocationStart != ELF_INVALID_RELOCATION) {
- ASSERT((Image->Flags & IMAGE_FLAG_TEXT_RELOCATIONS) != 0);
- ASSERT(LoadingImage->RelocationEnd != ELF_INVALID_RELOCATION);
- ASSERT(LoadingImage->RelocationEnd > LoadingImage->RelocationStart);
- Size = LoadingImage->RelocationEnd - LoadingImage->RelocationStart;
- ImInvalidateInstructionCacheRegion(LoadingImage->RelocationStart, Size);
- }
- return Status;
- }
- KSTATUS
- ImpElfProcessRelocateSection (
- PLIST_ENTRY ListHead,
- PLOADED_IMAGE Image,
- PVOID Relocations,
- ELF_XWORD RelocationsSize,
- BOOL Addends
- )
- /*++
- Routine Description:
- This routine processes the contents of a single relocation section.
- Arguments:
- ListHead - Supplies a pointer to the head of the list of loaded images.
- Image - Supplies a pointer to the loaded image structure.
- Relocations - Supplies a pointer to the relocations to apply.
- RelocationsSize - Supplies the size of the relocation section in bytes.
- Addends - Supplies a boolean indicating whether these are relocations with
- explicit addends (TRUE) or implicit addends (FALSE).
- Return Value:
- Status code.
- --*/
- {
- PELF_RELOCATION_ENTRY Relocation;
- PELF_RELOCATION_ADDEND_ENTRY RelocationAddend;
- ELF_XWORD RelocationCount;
- UINTN RelocationIndex;
- BOOL Result;
- RelocationAddend = Relocations;
- Relocation = Relocations;
- if (Addends != FALSE) {
- RelocationCount = RelocationsSize / sizeof(ELF_RELOCATION_ADDEND_ENTRY);
- } else {
- RelocationCount = RelocationsSize / sizeof(ELF_RELOCATION_ENTRY);
- }
- //
- // Process each relocation in the table.
- //
- for (RelocationIndex = 0;
- RelocationIndex < RelocationCount;
- RelocationIndex += 1) {
- if (Addends != FALSE) {
- Result = ImpElfApplyRelocation(ListHead,
- Image,
- RelocationAddend,
- TRUE,
- NULL);
- ASSERT(Result != FALSE);
- if (Result == FALSE) {
- return STATUS_INVALID_PARAMETER;
- }
- RelocationAddend += 1;
- } else {
- Result = ImpElfApplyRelocation(ListHead,
- Image,
- (PVOID)Relocation,
- FALSE,
- NULL);
- ASSERT(Result != FALSE);
- if (Result == FALSE) {
- return STATUS_INVALID_PARAMETER;
- }
- Relocation += 1;
- }
- }
- return STATUS_SUCCESS;
- }
- VOID
- ImpElfAdjustJumpSlots (
- PLOADED_IMAGE Image,
- PVOID Relocations,
- ELF_XWORD RelocationsSize,
- BOOL Addends
- )
- /*++
- Routine Description:
- This routine iterates over all the relocations in the PLT section and adds
- the base difference to them.
- Arguments:
- Image - Supplies a pointer to the loaded image structure.
- Relocations - Supplies a pointer to the relocations to apply.
- RelocationsSize - Supplies the size of the relocation section in bytes.
- Addends - Supplies a boolean indicating whether these are relocations with
- explicit addends (TRUE) or implicit addends (FALSE).
- Return Value:
- Status code.
- --*/
- {
- ELF_ADDR BaseDifference;
- ELF_XWORD Information;
- ELF_ADDR Offset;
- PELF_RELOCATION_ENTRY Relocation;
- PELF_RELOCATION_ADDEND_ENTRY RelocationAddend;
- ELF_XWORD RelocationCount;
- UINTN RelocationIndex;
- PELF_ADDR RelocationPlace;
- ELF_WORD RelocationType;
- BaseDifference = Image->BaseDifference;
- if (BaseDifference == 0) {
- return;
- }
- RelocationAddend = Relocations;
- Relocation = Relocations;
- if (Addends != FALSE) {
- RelocationCount = RelocationsSize /
- sizeof(ELF_RELOCATION_ADDEND_ENTRY);
- } else {
- RelocationCount = RelocationsSize / sizeof(ELF_RELOCATION_ENTRY);
- }
- //
- // Process each relocation in the table.
- //
- for (RelocationIndex = 0;
- RelocationIndex < RelocationCount;
- RelocationIndex += 1) {
- if (Addends != FALSE) {
- Offset = RelocationAddend->Offset;
- Information = RelocationAddend->Information;
- RelocationAddend += 1;
- } else {
- Offset = Relocation->Offset;
- Information = Relocation->Information;
- Relocation += 1;
- }
- RelocationType = ELF_GET_RELOCATION_TYPE(Information);
- //
- // If this is a jump slot relocation, bump it up by the base difference.
- //
- if (((Image->Machine == ImageMachineTypeArm32) &&
- (RelocationType == ElfArmRelocationJumpSlot)) ||
- ((Image->Machine == ImageMachineTypeX86) &&
- (RelocationType == Elf386RelocationJumpSlot))) {
- RelocationPlace = (PELF_ADDR)((PUCHAR)Image->LoadedImageBuffer +
- (Offset - (UINTN)Image->PreferredLowestAddress));
- *RelocationPlace += BaseDifference;
- }
- }
- return;
- }
- ELF_ADDR
- ImpElfGetSymbolValue (
- PLIST_ENTRY ListHead,
- PLOADED_IMAGE Image,
- PELF_SYMBOL Symbol,
- PLOADED_IMAGE *FoundImage,
- PLOADED_IMAGE SkipImage
- )
- /*++
- Routine Description:
- This routine determines the address of the given symbol.
- Arguments:
- ListHead - Supplies a pointer to the head of the list of loaded images.
- Image - Supplies a pointer to the loaded image.
- Symbol - Supplies a pointer to the symbol whose value should be computed.
- FoundImage - Supplies an optional pointer where the image where the symbol
- is defined will be returned on success.
- SkipImage - Supplies an optional pointer to an image to ignore when
- searching for a symbol definition. This is used in copy relocations
- when looking for the shared object version of a symbol defined in
- both the executable and a shared object.
- Return Value:
- Returns the symbol's value on success.
- ELF_INVALID_ADDRESS on failure.
- --*/
- {
- ELF_ADDR BaseDifference;
- ELF_SYMBOL_BIND_TYPE BindType;
- PLIST_ENTRY CurrentEntry;
- PLOADED_IMAGE CurrentImage;
- ULONG Hash;
- ULONG OriginalHash;
- PELF_SYMBOL Potential;
- CHAR PrintSymbolName[50];
- PSTR SymbolName;
- ELF_SYMBOL_TYPE SymbolType;
- ELF_ADDR Value;
- CurrentImage = NULL;
- BaseDifference = Image->BaseDifference;
- BindType = ELF_GET_SYMBOL_BIND(Symbol->Information);
- if (Symbol->NameOffset != 0) {
- SymbolName = Image->ExportStringTable + Symbol->NameOffset;
- if ((Image->Flags & IMAGE_FLAG_GNU_HASH) != 0) {
- Hash = ImpElfGnuHash(SymbolName);
- } else {
- Hash = ImpElfOriginalHash(SymbolName);
- }
- OriginalHash = Hash;
- CurrentEntry = ListHead->Next;
- if (BindType == ElfBindLocal) {
- ASSERT(SkipImage == NULL);
- CurrentEntry = &(Image->ListEntry);
- }
- while (CurrentEntry != ListHead) {
- CurrentImage = LIST_VALUE(CurrentEntry, LOADED_IMAGE, ListEntry);
- if (CurrentImage == SkipImage) {
- CurrentEntry = CurrentEntry->Next;
- continue;
- }
- //
- // If the two images disagree on hashing algorithms, then recompute
- // the hash for the image.
- //
- if (((CurrentImage->Flags ^ Image->Flags) &
- IMAGE_FLAG_GNU_HASH) != 0) {
- if ((CurrentImage->Flags & IMAGE_FLAG_GNU_HASH) != 0) {
- Hash = ImpElfGnuHash(SymbolName);
- } else {
- Hash = ImpElfOriginalHash(SymbolName);
- }
- }
- Potential = ImpElfGetSymbol(CurrentImage, Hash, SymbolName);
- Hash = OriginalHash;
- //
- // Don't match against the same undefined symbol in another image.
- //
- if ((Potential != NULL) && (Potential->SectionIndex != 0)) {
- //
- // TLS symbols are relative to their section base, and are
- // not adjusted.
- //
- SymbolType = ELF_GET_SYMBOL_TYPE(Symbol->Information);
- if (SymbolType == ElfSymbolTls) {
- Value = Potential->Value;
- goto ElfGetSymbolValueEnd;
- } else if (Potential->SectionIndex >=
- ELF_SECTION_RESERVED_LOW) {
- Value = ELF_INVALID_ADDRESS;
- if (Potential->SectionIndex == ELF_SECTION_ABSOLUTE) {
- Value = Potential->Value;
- }
- goto ElfGetSymbolValueEnd;
- }
- Value = Potential->Value + CurrentImage->BaseDifference;
- goto ElfGetSymbolValueEnd;
- }
- //
- // Don't look in other images if it's a local symbol.
- //
- if (BindType == ElfBindLocal) {
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- if (CurrentEntry == ListHead) {
- CurrentImage = NULL;
- }
- //
- // This symbol is not defined. If it's weak, that's okay. Otherwise,
- // that's a problem.
- //
- if (BindType != ElfBindWeak) {
- //
- // Copy the symbol name to the stack to avoid deadly faults during
- // debug print.
- //
- RtlStringCopy(PrintSymbolName, SymbolName, sizeof(PrintSymbolName));
- RtlDebugPrint("Warning: Unresolved reference to symbol %s.\n",
- PrintSymbolName);
- Value = ELF_INVALID_ADDRESS;
- } else {
- Value = 0;
- }
- goto ElfGetSymbolValueEnd;
- }
- //
- // If the section index is a reserved value, check to see if it's an
- // absolute symbol. If it is, just return the symbol value. Other reserved
- // values usually mean the symbol's value cannot be computed at this time.
- //
- if ((Symbol->SectionIndex == 0) ||
- (Symbol->SectionIndex >= ELF_SECTION_RESERVED_LOW)) {
- Value = ELF_INVALID_ADDRESS;
- if (Symbol->SectionIndex == ELF_SECTION_ABSOLUTE) {
- Value = Symbol->Value;
- }
- goto ElfGetSymbolValueEnd;
- }
- Value = Symbol->Value + BaseDifference;
- ElfGetSymbolValueEnd:
- if (FoundImage != NULL) {
- *FoundImage = CurrentImage;
- }
- return Value;
- }
- PELF_SYMBOL
- ImpElfGetSymbol (
- PLOADED_IMAGE Image,
- ULONG Hash,
- PSTR SymbolName
- )
- /*++
- Routine Description:
- This routine attempts to find an exported symbol with the given name in the
- given binary.
- Arguments:
- Image - Supplies a pointer to the image to query.
- Hash - Supplies the hashed symbol name.
- SymbolName - Supplies a pointer to the string containing the name of the
- symbol to search for.
- Return Value:
- Returns a pointer to the symbol on success.
- NULL if no such symbol was found.
- --*/
- {
- ELF_WORD BucketCount;
- ELF_WORD BucketIndex;
- BOOL Equal;
- PELF_WORD Filter;
- ELF_WORD FilterMask;
- ELF_WORD FilterWord;
- ELF_WORD FilterWords;
- PELF_WORD HashBuckets;
- PELF_WORD HashChains;
- PELF_WORD HashTable;
- PELF_SYMBOL Potential;
- ULONG PotentialHash;
- PSTR PotentialName;
- ULONG RemainingSize;
- ELF_WORD Shift;
- ELF_WORD SymbolBase;
- ELF_WORD SymbolIndex;
- ELF_WORD WordIndex;
- if (Image->ExportSymbolTable == NULL) {
- return NULL;
- }
- //
- // Handle GNU-style hashing.
- //
- if ((Image->Flags & IMAGE_FLAG_GNU_HASH) != 0) {
- HashTable = Image->ExportHashTable;
- BucketCount = *HashTable;
- HashTable += 1;
- SymbolBase = *HashTable;
- HashTable += 1;
- FilterWords = *HashTable;
- HashTable += 1;
- Shift = *HashTable;
- HashTable += 1;
- BucketIndex = Hash % BucketCount;
- //
- // Check the Bloom filter first. The Bloom filter indicates that a
- // symbol is definitely not there, or is maybe there. It basically
- // represents a quick "no".
- //
- Filter = (PELF_WORD)HashTable;
- HashTable = (PELF_WORD)(Filter + FilterWords);
- WordIndex = (Hash >> ELF_WORD_SIZE_SHIFT) & (FilterWords - 1);
- ASSERT(POWER_OF_2(FilterWords));
- FilterWord = Filter[WordIndex];
- FilterMask = (1 << (Hash & ELF_WORD_SIZE_MASK)) |
- (1 << ((Hash >> Shift) & ELF_WORD_SIZE_MASK));
- if ((FilterWord & FilterMask) != FilterMask) {
- return NULL;
- }
- //
- // The buckets contain the index of the first symbol with the given
- // hash.
- //
- SymbolIndex = HashTable[BucketIndex];
- if (SymbolIndex == 0) {
- return NULL;
- }
- if (SymbolIndex < SymbolBase) {
- ASSERT(FALSE);
- return NULL;
- }
- //
- // The chains then contain the hashes of each of the symbols, with the
- // low bit cleared. If the low bit is set, then the chain has ended.
- //
- HashChains = HashTable + BucketCount;
- do {
- PotentialHash = HashChains[SymbolIndex - SymbolBase];
- //
- // If the hash matches (ignoring the low bit), then do a full
- // comparison.
- //
- if (((PotentialHash ^ Hash) & ~0x1) == 0) {
- Potential = (PELF_SYMBOL)Image->ExportSymbolTable +
- SymbolIndex;
- PotentialName = Image->ExportStringTable +
- Potential->NameOffset;
- RemainingSize = Image->ExportStringTableSize -
- Potential->NameOffset;
- Equal = RtlAreStringsEqual(SymbolName,
- PotentialName,
- RemainingSize);
- if (Equal != FALSE) {
- return Potential;
- }
- }
- SymbolIndex += 1;
- } while ((PotentialHash & 0x1) == 0);
- //
- // Handle traditional SVR hashing.
- //
- } else {
- BucketCount = *((PELF_WORD)Image->ExportHashTable);
- HashBuckets = (PELF_WORD)Image->ExportHashTable + 2;
- HashChains = (PELF_WORD)Image->ExportHashTable + 2 + BucketCount;
- BucketIndex = Hash % BucketCount;
- SymbolIndex = *(HashBuckets + BucketIndex);
- while (SymbolIndex != 0) {
- Potential = (PELF_SYMBOL)Image->ExportSymbolTable + SymbolIndex;
- PotentialName = Image->ExportStringTable + Potential->NameOffset;
- RemainingSize = Image->ExportStringTableSize -
- Potential->NameOffset;
- Equal = RtlAreStringsEqual(SymbolName,
- PotentialName,
- RemainingSize);
- if (Equal != FALSE) {
- return Potential;
- }
- //
- // Get the next entry in the chain.
- //
- SymbolIndex = *(HashChains + SymbolIndex);
- }
- }
- return NULL;
- }
- BOOL
- ImpElfApplyRelocation (
- PLIST_ENTRY ListHead,
- PLOADED_IMAGE Image,
- PELF_RELOCATION_ADDEND_ENTRY RelocationEntry,
- BOOL AddendEntry,
- PVOID *FinalSymbolValue
- )
- /*++
- Routine Description:
- This routine applies a relocation entry to a loaded image.
- Arguments:
- ListHead - Supplies a pointer to the head of the list of loaded images.
- Image - Supplies a pointer to the loaded image structure.
- RelocationEntry - Supplies a pointer to the relocation entry. This should
- either be of type PELF_RELOCATION_ENTRY or
- PELF_RELOCATION_ADDEND_ENTRY depending on the Addends parameter.
- AddendEntry - Supplies a flag indicating that the entry if of type
- ELF_RELOCATION_ADDEND_ENTRY, not ELF_RELOCATION_ENTRY.
- FinalSymbolValue - Supplies an optional pointer where the symbol value will
- be returned on success. This is used by PLT relocations that are being
- fixed up on the fly and also need to jump directly to the symbol
- address.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- ELF_SXWORD Addend;
- BOOL AddendNeeded;
- ELF_ADDR Address;
- ELF_ADDR BaseDifference;
- BOOL Copy;
- ELF_XWORD Information;
- PELF_LOADING_IMAGE LoadingImage;
- ELF_ADDR Offset;
- ELF_ADDR Place;
- PVOID RelocationEnd;
- BOOL RelocationNeeded;
- PELF_ADDR RelocationPlace;
- ELF_XWORD RelocationType;
- PLOADED_IMAGE SymbolImage;
- ELF_XWORD SymbolIndex;
- PELF_SYMBOL Symbols;
- ELF_ADDR SymbolValue;
- Address = 0;
- LoadingImage = Image->ImageContext;
- BaseDifference = Image->BaseDifference;
- Offset = RelocationEntry->Offset;
- Information = RelocationEntry->Information;
- Addend = 0;
- if (AddendEntry != FALSE) {
- Addend = RelocationEntry->Addend;
- }
- //
- // The place is the actual VA of the relocation.
- //
- Place = BaseDifference + Offset;
- //
- // The Information field contains both the symbol index to the
- // relocation as well as the type of relocation to apply.
- //
- Symbols = Image->ExportSymbolTable;
- SymbolIndex = ELF_GET_RELOCATION_SYMBOL(Information);
- RelocationType = ELF_GET_RELOCATION_TYPE(Information);
- //
- // Compute the symbol value.
- //
- SymbolValue = ImpElfGetSymbolValue(ListHead,
- Image,
- &(Symbols[SymbolIndex]),
- &SymbolImage,
- NULL);
- if (SymbolValue == ELF_INVALID_ADDRESS) {
- SymbolValue = 0;
- }
- if (FinalSymbolValue != NULL) {
- *FinalSymbolValue = (PVOID)(UINTN)SymbolValue;
- }
- //
- // Based on the type of relocation, compute the relocated value.
- //
- Copy = FALSE;
- AddendNeeded = TRUE;
- RelocationNeeded = TRUE;
- if (Image->Machine == ImageMachineTypeArm32) {
- switch (RelocationType) {
- //
- // None is a no-op.
- //
- case ElfArmRelocationNone:
- RelocationNeeded = FALSE;
- break;
- //
- // The "copy" relocations copy data from a shared object into the
- // program's BSS segment. It is used by programs that reference
- // variables defined in a shared object (like stdin/out/err, environ,
- // etc). Note that copy can only work if this loader has access to the
- // source image address. As a clue assert that at least this image's
- // final address is the same as the address this code is accessing it
- // at.
- //
- case ElfArmRelocationCopy:
- ASSERT(Image->PreferredLowestAddress + BaseDifference ==
- Image->LoadedImageBuffer);
- //
- // Find the shared object version, not the executable version.
- //
- SymbolValue = ImpElfGetSymbolValue(ListHead,
- Image,
- &(Symbols[SymbolIndex]),
- NULL,
- Image);
- if (SymbolValue == ELF_INVALID_ADDRESS) {
- SymbolValue = 0;
- }
- Copy = TRUE;
- AddendNeeded = FALSE;
- Address = SymbolValue;
- break;
- //
- // Absolute uses only the symbol's value.
- //
- case ElfArmRelocationAbsolute32:
- Address = SymbolValue + Addend;
- break;
- //
- // Global relocations just use the symbol value. Jump slots are entries
- // in the Procedure Linkage Table (PLT), and also just use the symbol
- // value.
- //
- case ElfArmRelocationGlobalData:
- Address = SymbolValue;
- AddendNeeded = FALSE;
- break;
- case ElfArmRelocationJumpSlot:
- Address = SymbolValue;
- AddendNeeded = FALSE;
- break;
- //
- // Relative relocations just adjust for the new base.
- //
- case ElfArmRelocationRelative:
- Address = BaseDifference + Addend;
- break;
- //
- // This is the module ID.
- //
- case ElfArmRelocationTlsDtpMod32:
- if (SymbolImage == NULL) {
- SymbolImage = Image;
- }
- Address = SymbolImage->ModuleNumber;
- ASSERT(Address != 0);
- AddendNeeded = FALSE;
- break;
- //
- // This is the offset from the start of the TLS image to the given
- // symbol.
- //
- case ElfArmRelocationTlsDtpOff32:
- Address = SymbolValue + Addend;
- AddendNeeded = FALSE;
- break;
- //
- // This is the total offset from the thread pointer to the symbol, as
- // a positive value to be added to the thread pointer.
- //
- case ElfArmRelocationTlsTpOff32:
- if (SymbolImage == NULL) {
- SymbolImage = Image;
- }
- ASSERT((SymbolImage != NULL) &&
- (SymbolImage->TlsOffset != (UINTN)-1));
- //
- // The TLS offset is a positive value that indicates a negative
- // offset from the thread pointer, hence the subtraction here.
- //
- Address = SymbolValue - SymbolImage->TlsOffset + Addend;
- break;
- //
- // Unknown relocation type.
- //
- default:
- ASSERT(FALSE);
- return FALSE;
- }
- //
- // Handle x86 images.
- //
- } else if (Image->Machine == ImageMachineTypeX86) {
- switch (RelocationType) {
- //
- // None is a no-op.
- //
- case Elf386RelocationNone:
- RelocationNeeded = FALSE;
- break;
- //
- // Absolute uses only the symbol's value.
- //
- case Elf386Relocation32:
- Address = SymbolValue + Addend;
- break;
- //
- // PC32 is Symbol + Addend - Place
- //
- case Elf386RelocationPc32:
- Address = SymbolValue + Addend - Place;
- break;
- //
- // The "copy" relocations copy data from a shared object into the
- // program's BSS segment. It is used by programs that reference
- // variables defined in a shared object (like stdin/out/err, environ,
- // etc). Note that copy can only work if this loader has access to the
- // source image address. As a clue assert that at least this image's
- // final address is the same as the address this code is accessing it
- // at.
- //
- case Elf386RelocationCopy:
- ASSERT(Image->PreferredLowestAddress + BaseDifference ==
- Image->LoadedImageBuffer);
- //
- // Find the shared object version, not the executable version.
- //
- SymbolValue = ImpElfGetSymbolValue(ListHead,
- Image,
- &(Symbols[SymbolIndex]),
- NULL,
- Image);
- if (SymbolValue == ELF_INVALID_ADDRESS) {
- SymbolValue = 0;
- }
- Copy = TRUE;
- AddendNeeded = FALSE;
- Address = SymbolValue;
- break;
- //
- // Global relocations just use the symbol value. Jump slots are entries
- // in the Procedure Linkage Table (PLT), and also just use the symbol
- // value.
- //
- case Elf386RelocationGlobalData:
- Address = SymbolValue;
- AddendNeeded = FALSE;
- break;
- case Elf386RelocationJumpSlot:
- Address = SymbolValue;
- AddendNeeded = FALSE;
- break;
- //
- // Relative relocations just adjust for the new base.
- //
- case Elf386RelocationRelative:
- Address = BaseDifference + Addend;
- break;
- //
- // This is the module ID.
- //
- case Elf386RelocationTlsDtpMod32:
- if (SymbolImage == NULL) {
- SymbolImage = Image;
- }
- Address = SymbolImage->ModuleNumber;
- ASSERT(Address != 0);
- AddendNeeded = FALSE;
- break;
- //
- // This is the offset from the start of the TLS image to the given
- // symbol.
- //
- case Elf386RelocationTlsDtpOff32:
- Address = SymbolValue + Addend;
- AddendNeeded = FALSE;
- break;
- //
- // This is the total offset from the thread pointer to the symbol, as
- // a negative value to be added to the thread pointer.
- //
- case Elf386RelocationTlsTpOff:
- if (SymbolImage == NULL) {
- SymbolImage = Image;
- }
- ASSERT((SymbolImage != NULL) &&
- (SymbolImage->TlsOffset != (UINTN)-1));
- Address = SymbolValue - SymbolImage->TlsOffset + Addend;
- break;
- //
- // This is the total offset from the thread pointer to the symbol, as
- // a positive value to be subtracted from the thread pointer.
- //
- case Elf386RelocationTlsTpOff32:
- if (SymbolImage == NULL) {
- SymbolImage = Image;
- }
- ASSERT((SymbolImage != NULL) &&
- (SymbolImage->TlsOffset != (UINTN)-1));
- Address = SymbolImage->TlsOffset - SymbolValue + Addend;
- break;
- //
- // Unknown relocation type.
- //
- default:
- ASSERT(FALSE);
- return FALSE;
- }
- } else {
- ASSERT(FALSE);
- return FALSE;
- }
- //
- // If a relocation is needed, apply it now.
- //
- if (RelocationNeeded != FALSE) {
- RelocationPlace = (PELF_ADDR)((PUCHAR)Image->LoadedImageBuffer +
- (Offset - (UINTN)Image->PreferredLowestAddress));
- if (AddendNeeded != FALSE) {
- Address += *RelocationPlace;
- }
- if (Copy != FALSE) {
- RtlCopyMemory(RelocationPlace,
- (PVOID)(UINTN)Address,
- Symbols[SymbolIndex].Size);
- RelocationEnd = (PVOID)RelocationPlace +
- Symbols[SymbolIndex].Size;
- } else {
- //
- // Avoid the write unless it's necessary, as unnecessary write
- // faults are expensive.
- //
- if (*RelocationPlace != Address) {
- *RelocationPlace = Address;
- RelocationEnd = RelocationPlace + 1;
- } else {
- RelocationEnd = NULL;
- }
- }
- if ((LoadingImage != NULL) &&
- ((Image->Flags & IMAGE_FLAG_TEXT_RELOCATIONS) != 0) &&
- (RelocationEnd != NULL)) {
- if ((LoadingImage->RelocationStart == ELF_INVALID_RELOCATION) ||
- (LoadingImage->RelocationStart > (PVOID)RelocationPlace)) {
- LoadingImage->RelocationStart = RelocationPlace;
- }
- if ((LoadingImage->RelocationEnd == ELF_INVALID_RELOCATION) ||
- (LoadingImage->RelocationEnd < RelocationEnd)) {
- LoadingImage->RelocationEnd = RelocationEnd;
- }
- }
- }
- return TRUE;
- }
- VOID
- ImpElfFreeContext (
- PLOADED_IMAGE Image
- )
- /*++
- Routine Description:
- This routine frees the loading image context, and closes and unloads the
- file.
- Arguments:
- Image - Supplies a pointer to the image that has finished loading.
- Return Value:
- None.
- --*/
- {
- PELF_LOADING_IMAGE LoadingImage;
- if (Image->ImageContext != NULL) {
- LoadingImage = Image->ImageContext;
- if (Image->File.Handle != INVALID_HANDLE) {
- if (LoadingImage->Buffer.Data != NULL) {
- ImUnloadBuffer(&(Image->File), &(LoadingImage->Buffer));
- }
- ImCloseFile(&(Image->File));
- Image->File.Handle = INVALID_HANDLE;
- }
- LoadingImage->Buffer.Data = NULL;
- LoadingImage = NULL;
- ImFreeMemory(Image->ImageContext);
- Image->ImageContext = NULL;
- }
- return;
- }
|