+//\r
+// Find the ELF section hosting the GOT from an ELF Rva\r
+// of a single GOT entry. Normally, GOT is placed in\r
+// ELF .text section, so assume once we find in which\r
+// section the GOT is, all GOT entries are there, and\r
+// just verify this.\r
+//\r
+STATIC\r
+VOID\r
+FindElfGOTSectionFromGOTEntryElfRva (\r
+ Elf64_Addr GOTEntryElfRva\r
+ )\r
+{\r
+ UINT32 i;\r
+ if (mGOTShdr != NULL) {\r
+ if (GOTEntryElfRva >= mGOTShdr->sh_addr &&\r
+ GOTEntryElfRva < mGOTShdr->sh_addr + mGOTShdr->sh_size) {\r
+ return;\r
+ }\r
+ Error (NULL, 0, 3000, "Unsupported", "FindElfGOTSectionFromGOTEntryElfRva: GOT entries found in multiple sections.");\r
+ exit(EXIT_FAILURE);\r
+ }\r
+ for (i = 0; i < mEhdr->e_shnum; i++) {\r
+ Elf_Shdr *shdr = GetShdrByIndex(i);\r
+ if (GOTEntryElfRva >= shdr->sh_addr &&\r
+ GOTEntryElfRva < shdr->sh_addr + shdr->sh_size) {\r
+ mGOTShdr = shdr;\r
+ mGOTShindex = i;\r
+ return;\r
+ }\r
+ }\r
+ Error (NULL, 0, 3000, "Invalid", "FindElfGOTSectionFromGOTEntryElfRva: ElfRva 0x%016LX for GOT entry not found in any section.", GOTEntryElfRva);\r
+ exit(EXIT_FAILURE);\r
+}\r
+\r
+//\r
+// Stores locations of GOT entries in COFF image.\r
+// Returns TRUE if GOT entry is new.\r
+// Simple implementation as number of GOT\r
+// entries is expected to be low.\r
+//\r
+\r
+STATIC\r
+BOOLEAN\r
+AccumulateCoffGOTEntries (\r
+ UINT32 GOTCoffEntry\r
+ )\r
+{\r
+ UINT32 i;\r
+ if (mGOTCoffEntries != NULL) {\r
+ for (i = 0; i < mGOTNumCoffEntries; i++) {\r
+ if (mGOTCoffEntries[i] == GOTCoffEntry) {\r
+ return FALSE;\r
+ }\r
+ }\r
+ }\r
+ if (mGOTCoffEntries == NULL) {\r
+ mGOTCoffEntries = (UINT32*)malloc(5 * sizeof *mGOTCoffEntries);\r
+ if (mGOTCoffEntries == NULL) {\r
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+ }\r
+ assert (mGOTCoffEntries != NULL);\r
+ mGOTMaxCoffEntries = 5;\r
+ mGOTNumCoffEntries = 0;\r
+ } else if (mGOTNumCoffEntries == mGOTMaxCoffEntries) {\r
+ mGOTCoffEntries = (UINT32*)realloc(mGOTCoffEntries, 2 * mGOTMaxCoffEntries * sizeof *mGOTCoffEntries);\r
+ if (mGOTCoffEntries == NULL) {\r
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+ }\r
+ assert (mGOTCoffEntries != NULL);\r
+ mGOTMaxCoffEntries += mGOTMaxCoffEntries;\r
+ }\r
+ mGOTCoffEntries[mGOTNumCoffEntries++] = GOTCoffEntry;\r
+ return TRUE;\r
+}\r
+\r
+//\r
+// 32-bit Unsigned integer comparator for qsort.\r
+//\r
+STATIC\r
+int\r
+UINT32Comparator (\r
+ const void* lhs,\r
+ const void* rhs\r
+ )\r
+{\r
+ if (*(const UINT32*)lhs < *(const UINT32*)rhs) {\r
+ return -1;\r
+ }\r
+ return *(const UINT32*)lhs > *(const UINT32*)rhs;\r
+}\r
+\r
+//\r
+// Emit accumulated Coff GOT entry relocations into\r
+// Coff image. This function performs its job\r
+// once and then releases the entry list, so\r
+// it can safely be called multiple times.\r
+//\r
+STATIC\r
+VOID\r
+EmitGOTRelocations (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 i;\r
+ if (mGOTCoffEntries == NULL) {\r
+ return;\r
+ }\r
+ //\r
+ // Emit Coff relocations with Rvas ordered.\r
+ //\r
+ qsort(\r
+ mGOTCoffEntries,\r
+ mGOTNumCoffEntries,\r
+ sizeof *mGOTCoffEntries,\r
+ UINT32Comparator);\r
+ for (i = 0; i < mGOTNumCoffEntries; i++) {\r
+ VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", mGOTCoffEntries[i]);\r
+ CoffAddFixup(\r
+ mGOTCoffEntries[i],\r
+ EFI_IMAGE_REL_BASED_DIR64);\r
+ }\r
+ free(mGOTCoffEntries);\r
+ mGOTCoffEntries = NULL;\r
+ mGOTMaxCoffEntries = 0;\r
+ mGOTNumCoffEntries = 0;\r
+}\r
+\r