Usermode/libc #6 Fix string.h functions, add some more unit tests
[tpg/acess2.git] / Usermode / Libraries / ld-acess.so_src / pe.c
1 /*\r
2  * Acess v1\r
3  * Portable Executable Loader\r
4  */\r
5 #include "common.h"\r
6 #include <stdint.h>\r
7 #include "pe.h"\r
8 \r
9 #define PE_DEBUG        0\r
10 #define DEBUG   (ACESS_DEBUG|PE_DEBUG)\r
11 \r
12 //#define DLL_BASE_PATH "/Acess/Windows/"\r
13 #define DLL_BASE_PATH   NULL\r
14 \r
15 #if DEBUG\r
16 # define DEBUGS(v...)   SysDebug(v)\r
17 #else\r
18 # define DEBUGS(v...)\r
19 #endif\r
20 \r
21 // === PROTOTYPES ===\r
22 void    *PE_Relocate(void *Base, char **envp, const char *Filename);\r
23 char    *PE_int_GetTrueFile(char *file);\r
24  int    PE_int_GetForwardSymbol(char *Fwd, void **Value);\r
25 \r
26 // === CODE ===\r
27 void *PE_Relocate(void *Base, char **envp, const char *Filename)\r
28 {\r
29         tPE_DOS_HEADER          *dosHdr = Base;\r
30         tPE_IMAGE_HEADERS       *peHeaders;\r
31         tPE_DATA_DIR    *directory;\r
32         tPE_IMPORT_DIR  *impDir;\r
33         tPE_HINT_NAME   *name;\r
34         Uint32  *importTab, *aIAT;\r
35          int    i, j;\r
36         intptr_t        iBase = (intptr_t)Base;\r
37         void    *pLibBase;\r
38         \r
39         DEBUGS("PE_Relocate: (Base=0x%x)\n", Base);\r
40         \r
41         peHeaders = Base + dosHdr->PeHdrOffs;\r
42         \r
43         directory = peHeaders->OptHeader.Directory;\r
44         \r
45         // === Load Import Tables\r
46         impDir = Base + directory[PE_DIR_IMPORT].RVA;\r
47         for( i = 0; impDir[i].DLLName != NULL; i++ )\r
48         {\r
49                 impDir[i].DLLName += iBase;\r
50                 impDir[i].ImportLookupTable += iBase/4;\r
51                 impDir[i].ImportAddressTable += iBase/4;\r
52                 DEBUGS(" PE_Relocate: DLL Required '%s'(0x%x)\n", impDir[i].DLLName, impDir[i].DLLName);\r
53                 pLibBase = LoadLibrary(PE_int_GetTrueFile(impDir[i].DLLName), DLL_BASE_PATH, envp);\r
54                 if(pLibBase == 0) {\r
55                         SysDebug("Unable to load required library '%s'\n", impDir[i].DLLName);\r
56                         return 0;\r
57                 }\r
58                 DEBUGS(" PE_Relocate: Loaded as 0x%x\n", pLibBase);\r
59                 importTab = impDir[i].ImportLookupTable;\r
60                 aIAT = impDir[i].ImportAddressTable;\r
61                 for( j = 0; importTab[j] != 0; j++ )\r
62                 {\r
63                         if( importTab[j] & 0x80000000 )\r
64                                 DEBUGS(" PE_Relocate: Import Ordinal %i\n", importTab[j] & 0x7FFFFFFF);\r
65                         else\r
66                         {\r
67                                 void    *symPtr = 0;\r
68                                 name = (void*)( iBase + importTab[j] );\r
69                                 DEBUGS(" PE_Relocate: Import Name '%s', Hint 0x%x\n", name->Name, name->Hint);\r
70                                 if( GetSymbolFromBase(pLibBase, name->Name, symPtr, NULL) == 0 )\r
71                                 {\r
72                                         SysDebug("Unable to find symbol '%s' in library '%s'\n", name->Name, impDir[i].DLLName);\r
73                                         return 0;\r
74                                 }\r
75                                 aIAT[j] = (intptr_t)symPtr;\r
76                         }\r
77                 }\r
78         }\r
79         \r
80         #if DEBUG\r
81         for(i=0;i<PE_DIR_LAST;i++) {\r
82                 if(directory[i].RVA == 0)       continue;\r
83                 SysDebug("directory[%i] = {RVA=0x%x,Size=0x%x}\n", i, directory[i].RVA, directory[i].Size);\r
84         }\r
85         #endif\r
86         \r
87         DEBUGS("PE_Relocate: RETURN 0x%x\n", iBase + peHeaders->OptHeader.EntryPoint);\r
88         \r
89         return (void*)( iBase + peHeaders->OptHeader.EntryPoint );\r
90 }\r
91 \r
92 /**\r
93  * \fn int PE_GetSymbol(Uint Base, const char *Name, Uint *Ret)\r
94  */\r
95 int PE_GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size)\r
96 {\r
97         tPE_DOS_HEADER          *dosHdr = Base;\r
98         tPE_IMAGE_HEADERS       *peHeaders;\r
99         tPE_DATA_DIR    *directory;\r
100         tPE_EXPORT_DIR  *expDir;\r
101         Uint32  *nameTable, *addrTable;\r
102         Uint16  *ordTable;\r
103          int    i;\r
104          int    symbolCount;\r
105         char    *name;\r
106         intptr_t        retVal;\r
107         Uint    expLen;\r
108         \r
109         peHeaders = (void*)( Base + dosHdr->PeHdrOffs );\r
110         directory = peHeaders->OptHeader.Directory;\r
111         \r
112         expDir = (void*)( Base + directory[PE_DIR_EXPORT].RVA );\r
113         expLen = directory[PE_DIR_EXPORT].Size;\r
114         symbolCount = expDir->NumNamePointers;\r
115         nameTable = (void*)( Base + expDir->NamePointerRVA );\r
116         ordTable = (void*)( Base + expDir->OrdinalTableRVA );\r
117         addrTable = (void*)( Base + expDir->AddressRVA );\r
118         //DEBUGS(" PE_GetSymbol: %i Symbols\n", symbolCount);\r
119         for(i=0;i<symbolCount;i++)\r
120         {\r
121                 name = (char*)( Base + nameTable[i] );\r
122                 //DEBUGS(" PE_GetSymbol: '%s' = 0x%x\n", name, Base + addrTable[ ordTable[i] ]);\r
123                 if(strcmp(name, Name) == 0)\r
124                 {\r
125                         retVal = (intptr_t) Base + addrTable[ ordTable[i] ];\r
126                         // Check for forwarding\r
127                         if( (intptr_t)expDir < retVal && retVal < (intptr_t)expDir + expLen) {\r
128                                 char *fwd = (char*)retVal;\r
129                                 DEBUGS(" PE_GetSymbol: '%s' forwards to '%s'\n", name, fwd);\r
130                                 return PE_int_GetForwardSymbol(fwd, Ret);\r
131                         }\r
132                         *Ret = (void*)retVal;\r
133                         if(Size)        *Size = 0;\r
134                         return 1;\r
135                 }\r
136         }\r
137         return 0;\r
138 }\r
139 \r
140 /**\r
141  * \fn char *PE_int_GetTrueFile(char *file)\r
142  * \brief Get the true file name\r
143  */\r
144 char *PE_int_GetTrueFile(char *file)\r
145 {\r
146          int    i;\r
147         if(file[0] != ':')      return file;\r
148 \r
149         // Translate name\r
150         for(i=1;file[i];i++)\r
151                 if(file[i] == '_')\r
152                         file[i] = '.';\r
153         \r
154         return &file[1];\r
155 }\r
156 \r
157 int PE_int_GetForwardSymbol(char *Fwd, void **Value)\r
158 {\r
159         char    *libname;\r
160         char    *sym;\r
161          int    i;\r
162         void    *libbase;\r
163          int    ret;\r
164         \r
165         // -- Find seperator\r
166         // PE spec says that there sould only be one, but the string may\r
167         // be mutilated in the loader\r
168         for(i=0;Fwd[i]!='\0';i++);\r
169         for(;i&&Fwd[i]!='.';i--);\r
170         \r
171         Fwd[i] = '\0';\r
172         sym = &Fwd[i+1];\r
173         \r
174         libname = PE_int_GetTrueFile(Fwd);\r
175         \r
176         DEBUGS(" PE_int_GetForwardSymbol: Get '%s' from '%s'\n", sym, libname);\r
177         \r
178         libbase = LoadLibrary(libname, DLL_BASE_PATH, NULL);\r
179         ret = GetSymbolFromBase(libbase, sym, Value, NULL);\r
180         if(!ret) {\r
181                 SysDebug(" PE_int_GetForwardSymbol: Unable to find '%s' in '%s'\n", sym, libname);\r
182                 return 0;\r
183         }\r
184         Fwd[i] = '.';\r
185         return ret;\r
186 }\r

UCC git Repository :: git.ucc.asn.au