OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
Link.c
Go to the documentation of this file.
1
15#include <Base.h>
16
19
20#include <Library/BaseLib.h>
21#include <Library/BaseMemoryLib.h>
22#include <Library/BaseOverflowLib.h>
23#include <Library/DebugLib.h>
25#include <Library/OcMachoLib.h>
26
27#include <Library/OcFileLib.h>
28
29#include "PrelinkedInternal.h"
30
31#define TEXT_SEG_PROT (MACH_SEGMENT_VM_PROT_READ | MACH_SEGMENT_VM_PROT_EXECUTE)
32#define DATA_SEG_PROT (MACH_SEGMENT_VM_PROT_READ | MACH_SEGMENT_VM_PROT_WRITE)
33
34//
35// Symbols
36//
37
38STATIC
41 IN PRELINKED_KEXT *Kext,
42 IN CONST CHAR8 *LookupValue,
43 IN UINT32 LookupValueLength,
44 IN OC_GET_SYMBOL_LEVEL SymbolLevel
45 )
46{
47 PRELINKED_KEXT *Dependency;
48 CONST PRELINKED_KEXT_SYMBOL *Symbols;
49 CONST PRELINKED_KEXT_SYMBOL *SymbolsEnd;
50 UINT32 Index;
51 UINT32 NumSymbols;
52
53 //
54 // Block any 1+ level dependencies.
55 //
56 Kext->Processed = TRUE;
57
58 if (Kext->LinkedSymbolTable != NULL) {
59 NumSymbols = Kext->NumberOfSymbols;
60 Symbols = Kext->LinkedSymbolTable;
61
62 if (SymbolLevel == OcGetSymbolOnlyCxx) {
63 NumSymbols = Kext->NumberOfCxxSymbols;
64 Symbols = &Kext->LinkedSymbolTable[Kext->NumberOfSymbols - Kext->NumberOfCxxSymbols];
65 }
66
67 SymbolsEnd = &Symbols[NumSymbols];
68 while (Symbols < SymbolsEnd) {
69 //
70 // Symbol names often start and end similarly due to C++ mangling (e.g. __ZN).
71 // To optimise the lookup we compare their length check in the middle.
72 // Please do not change this without careful profiling.
73 //
74 if (Symbols->Length == LookupValueLength) {
75 if ( (Symbols->Name[LookupValueLength / 2] == LookupValue[LookupValueLength / 2])
76 && (Symbols->Name[(LookupValueLength / 2) + 1] == LookupValue[(LookupValueLength / 2) + 1]))
77 {
78 for (Index = 0; Index < LookupValueLength; ++Index) {
79 if (Symbols->Name[Index] != LookupValue[Index]) {
80 break;
81 }
82 }
83
84 if (Index == LookupValueLength) {
85 return Symbols;
86 }
87 }
88 }
89
90 Symbols++;
91 }
92 }
93
94 if (SymbolLevel != OcGetSymbolFirstLevel) {
95 for (Index = 0; Index < ARRAY_SIZE (Kext->Dependencies); ++Index) {
96 Dependency = Kext->Dependencies[Index];
97 if (Dependency == NULL) {
98 return NULL;
99 }
100
101 if (Dependency->Processed) {
102 continue;
103 }
104
106 Dependency,
107 LookupValue,
108 LookupValueLength,
110 );
111 if (Symbols != NULL) {
112 return Symbols;
113 }
114 }
115 }
116
117 return NULL;
118}
119
120STATIC
123 IN PRELINKED_KEXT *Kext,
124 IN UINT64 LookupValue,
125 IN OC_GET_SYMBOL_LEVEL SymbolLevel
126 )
127{
128 PRELINKED_KEXT *Dependency;
129 CONST PRELINKED_KEXT_SYMBOL *Symbols;
130 CONST PRELINKED_KEXT_SYMBOL *SymbolsEnd;
131 UINT32 Index;
132 UINT32 NumSymbols;
133
134 //
135 // Block any 1+ level dependencies.
136 //
137 Kext->Processed = TRUE;
138
139 if (Kext->LinkedSymbolTable != NULL) {
140 NumSymbols = Kext->NumberOfSymbols;
141 Symbols = Kext->LinkedSymbolTable;
142
143 if (SymbolLevel == OcGetSymbolOnlyCxx) {
144 NumSymbols = Kext->NumberOfCxxSymbols;
145 Symbols = &Kext->LinkedSymbolTable[(Kext->NumberOfSymbols - Kext->NumberOfCxxSymbols) & ~15ULL];
146 }
147
148 //
149 // WARN! Hot path! Do not change this code unless you have decent profiling data.
150 // We are not allowed to use SIMD in UEFI, but we can still do better with larger iteration.
151 // Up to 15 C symbols extra may get parsed, but it is fine, as they will not match.
152 // Increasing the iteration block to more than 16 no longer pays off.
153 // Note, lower loop is not on hot path.
154 //
155 SymbolsEnd = &Symbols[NumSymbols & ~15ULL];
156 while (Symbols < SymbolsEnd) {
157 #define MATCH(X) if (Symbols[X].Value == LookupValue) { return &Symbols[X]; }
158 MATCH (0) MATCH (1) MATCH (2) MATCH (3) MATCH (4) MATCH (5) MATCH (6) MATCH (7)
159 MATCH (8) MATCH (9) MATCH (10) MATCH (11) MATCH (12) MATCH (13) MATCH (14) MATCH (15)
160 #undef MATCH
161 Symbols += 16;
162 }
163 }
164
165 if (SymbolLevel != OcGetSymbolFirstLevel) {
166 for (Index = 0; Index < ARRAY_SIZE (Kext->Dependencies); ++Index) {
167 Dependency = Kext->Dependencies[Index];
168 if (Dependency == NULL) {
169 return NULL;
170 }
171
172 if (Dependency->Processed) {
173 continue;
174 }
175
177 Dependency,
178 LookupValue,
180 );
181 if (Symbols != NULL) {
182 return Symbols;
183 }
184 }
185 }
186
187 return NULL;
188}
189
192 IN PRELINKED_CONTEXT *Context,
193 IN PRELINKED_KEXT *Kext,
194 IN CONST CHAR8 *LookupValue,
195 IN OC_GET_SYMBOL_LEVEL SymbolLevel
196 )
197{
198 CONST PRELINKED_KEXT_SYMBOL *Symbol;
199
200 PRELINKED_KEXT *Dependency;
201 UINT32 Index;
202 UINT32 LookupValueLength;
203
204 Symbol = NULL;
205 LookupValueLength = (UINT32)AsciiStrLen (LookupValue);
206
207 //
208 // Such symbols are illegit, but InternalOcGetSymbolWorkerName assumes Length > 0.
209 //
210 if (LookupValueLength == 0) {
211 return NULL;
212 }
213
214 if ((SymbolLevel == OcGetSymbolOnlyCxx) && (Kext->LinkedSymbolTable != NULL)) {
216 Kext,
217 LookupValue,
218 LookupValueLength,
219 SymbolLevel
220 );
221 } else {
222 for (Index = 0; Index < ARRAY_SIZE (Kext->Dependencies); ++Index) {
223 Dependency = Kext->Dependencies[Index];
224 if (Dependency == NULL) {
225 break;
226 }
227
229 Dependency,
230 LookupValue,
231 LookupValueLength,
232 SymbolLevel
233 );
234 if (Symbol != NULL) {
235 break;
236 }
237 }
238 }
239
241
242 return Symbol;
243}
244
247 IN PRELINKED_CONTEXT *Context,
248 IN PRELINKED_KEXT *Kext,
249 IN UINT64 LookupValue,
250 IN OC_GET_SYMBOL_LEVEL SymbolLevel
251 )
252{
253 CONST PRELINKED_KEXT_SYMBOL *Symbol;
254
255 PRELINKED_KEXT *Dependency;
256 UINT32 Index;
257
258 Symbol = NULL;
259
260 if ((SymbolLevel == OcGetSymbolOnlyCxx) && (Kext->LinkedSymbolTable != NULL)) {
261 Symbol = InternalOcGetSymbolWorkerValue (Kext, LookupValue, SymbolLevel);
262 } else {
263 for (Index = 0; Index < ARRAY_SIZE (Kext->Dependencies); ++Index) {
264 Dependency = Kext->Dependencies[Index];
265 if (Dependency == NULL) {
266 break;
267 }
268
270 Dependency,
271 LookupValue,
272 SymbolLevel
273 );
274 if (Symbol != NULL) {
275 break;
276 }
277 }
278 }
279
281
282 return Symbol;
283}
284
293VOID
295 IN BOOLEAN Is32Bit,
296 IN UINT64 Value,
297 OUT MACH_NLIST_ANY *Symbol
298 )
299{
300 if (Is32Bit) {
301 Symbol->Symbol32.Value = (UINT32)Value;
302 Symbol->Symbol32.Type = (MACH_N_TYPE_ABS | MACH_N_TYPE_EXT);
303 Symbol->Symbol32.Section = NO_SECT;
304 } else {
305 Symbol->Symbol64.Value = Value;
306 Symbol->Symbol64.Type = (MACH_N_TYPE_ABS | MACH_N_TYPE_EXT);
307 Symbol->Symbol64.Section = NO_SECT;
308 }
309}
310
323STATIC
324BOOLEAN
326 IN PRELINKED_CONTEXT *Context,
327 IN PRELINKED_KEXT *Kext,
328 IN CONST CHAR8 *Name,
329 IN OUT MACH_NLIST_ANY *Symbol
330 )
331{
332 INTN Result;
333 CONST PRELINKED_KEXT_SYMBOL *ResolveSymbol;
334 UINT8 SymbolType;
335
336 SymbolType = Context->Is32Bit ? Symbol->Symbol32.Type : Symbol->Symbol64.Type;
337
338 if ((SymbolType & MACH_N_TYPE_TYPE) != MACH_N_TYPE_UNDF) {
339 if ((SymbolType & MACH_N_TYPE_TYPE) != MACH_N_TYPE_INDR) {
340 //
341 // KXLD_WEAK_TEST_SYMBOL might have been resolved by the resolving code
342 // at the end of InternalSolveSymbol.
343 //
344 Result = AsciiStrCmp (
345 MachoGetSymbolName (&Kext->Context.MachContext, Symbol),
347 );
348 if (Result == 0) {
349 //
350 // KXLD_WEAK_TEST_SYMBOL has been solved successfully already.
351 //
352 return TRUE;
353 }
354
355 //
356 // Any other symbols must be undefined or indirect.
357 //
358 return FALSE;
359 }
360 } else if ((Context->Is32Bit ? Symbol->Symbol32.Value : Symbol->Symbol64.Value) != 0) {
361 //
362 // Common symbols are not supported.
363 //
364 return FALSE;
365 }
366
367 //
368 // Do not error when the referenced symbol cannot be found as some will be
369 // patched by the VTable code. This matches the KXLD behaviour.
370 //
371 ResolveSymbol = InternalOcGetSymbolName (
372 Context,
373 Kext,
374 Name,
376 );
377 if (ResolveSymbol != NULL) {
378 InternalSolveSymbolValue (Context->Is32Bit, ResolveSymbol->Value, Symbol);
379 }
380
381 return TRUE;
382}
383
402STATIC
403BOOLEAN
405 IN PRELINKED_CONTEXT *Context,
406 IN PRELINKED_KEXT *Kext,
407 IN CONST CHAR8 *Name,
408 IN OUT MACH_NLIST_ANY *Symbol,
409 IN OUT UINT64 *WeakTestValue,
410 IN CONST MACH_NLIST_ANY *UndefinedSymbols,
411 IN UINT32 NumUndefinedSymbols
412 )
413{
414 BOOLEAN Success;
415 UINT32 Index;
416 INTN Result;
417 UINT64 Value;
418 CONST MACH_NLIST_ANY *WeakTestSymbol;
419
420 ASSERT (Symbol != NULL);
421 ASSERT (UndefinedSymbols != NULL || NumUndefinedSymbols == 0);
422 //
423 // STAB symbols are not considered undefined.
424 //
425 if (((Context->Is32Bit ? Symbol->Symbol32.Type : Symbol->Symbol64.Type) & MACH_N_TYPE_STAB) != 0) {
426 return TRUE;
427 }
428
430 Context,
431 Kext,
432 Name,
433 Symbol
434 );
435 if (Success) {
436 return TRUE;
437 }
438
439 if (((Context->Is32Bit ? Symbol->Symbol32.Descriptor : Symbol->Symbol64.Descriptor) & MACH_N_WEAK_DEF) != 0) {
440 //
441 // KXLD_WEAK_TEST_SYMBOL is not going to be defined or exposed by a KEXT
442 // prelinked by this library, hence only check the undefined symbols region
443 // for matches.
444 //
445 Value = *WeakTestValue;
446
447 if (Value == 0) {
448 //
449 // Fallback to the primary symbol table if we do not have a separate undefined symbol table, but only on 32-bit.
450 //
451 if (NumUndefinedSymbols > 0) {
452 for (Index = 0; Index < NumUndefinedSymbols; ++Index) {
453 if (Context->Is32Bit) {
454 WeakTestSymbol = (MACH_NLIST_ANY *)&(&UndefinedSymbols->Symbol32)[Index];
455 } else {
456 WeakTestSymbol = (MACH_NLIST_ANY *)&(&UndefinedSymbols->Symbol64)[Index];
457 }
458
459 Result = AsciiStrCmp (
461 &Kext->Context.MachContext,
462 WeakTestSymbol
463 ),
465 );
466 if (Result == 0) {
467 if (((Context->Is32Bit ?
468 WeakTestSymbol->Symbol32.Descriptor : WeakTestSymbol->Symbol64.Descriptor) & MACH_N_TYPE_TYPE) == MACH_N_TYPE_UNDF)
469 {
471 Context,
472 Kext,
473 Name,
474 Symbol
475 );
476 if (!Success) {
477 return FALSE;
478 }
479 }
480
481 Value = Context->Is32Bit ? WeakTestSymbol->Symbol32.Value : WeakTestSymbol->Symbol64.Value;
482 *WeakTestValue = Value;
483 break;
484 }
485 }
486 } else if (Context->Is32Bit) {
487 Index = 0;
488 while (TRUE) {
489 WeakTestSymbol = MachoGetSymbolByIndex (&Kext->Context.MachContext, Index);
490 if (WeakTestSymbol == NULL) {
491 break;
492 }
493
494 Result = AsciiStrCmp (
496 &Kext->Context.MachContext,
497 WeakTestSymbol
498 ),
500 );
501 if (Result == 0) {
502 if (((Context->Is32Bit ?
503 WeakTestSymbol->Symbol32.Descriptor : WeakTestSymbol->Symbol64.Descriptor) & MACH_N_TYPE_TYPE) == MACH_N_TYPE_UNDF)
504 {
506 Context,
507 Kext,
508 Name,
509 Symbol
510 );
511 if (!Success) {
512 return FALSE;
513 }
514 }
515
516 Value = Context->Is32Bit ? WeakTestSymbol->Symbol32.Value : WeakTestSymbol->Symbol64.Value;
517 *WeakTestValue = Value;
518 break;
519 }
520
521 ++Index;
522 }
523 }
524 }
525
526 if (Value != 0) {
527 InternalSolveSymbolValue (Context->Is32Bit, Value, Symbol);
528 return TRUE;
529 }
530 }
531
532 return FALSE;
533}
534
535//
536// Relocations
537//
538
552STATIC
553BOOLEAN
555 IN UINT64 Target,
556 IN UINT64 Adjustment,
557 IN OUT INT32 *Instruction
558 )
559{
560 INT64 Displacement;
561 UINT64 Difference;
562
563 ASSERT (Instruction != NULL);
564
565 Displacement = ((*Instruction + Target) - Adjustment);
566 Difference = ABS (Displacement);
567
568 if (Difference >= X86_64_RIP_RELATIVE_LIMIT) {
569 return FALSE;
570 }
571
572 *Instruction = (INT32)Displacement;
573
574 return TRUE;
575}
576
594STATIC
595BOOLEAN
597 IN PRELINKED_CONTEXT *Context,
598 IN OUT PRELINKED_KEXT *Kext,
599 IN UINT64 LoadAddress,
600 IN CONST MACH_RELOCATION_INFO *Relocation,
601 IN CONST MACH_RELOCATION_INFO *NextRelocation OPTIONAL,
602 OUT UINT64 *Target,
603 OUT UINT64 *PairTarget,
604 OUT CONST PRELINKED_VTABLE **Vtable OPTIONAL
605 )
606{
607 BOOLEAN Success;
608
609 OC_MACHO_CONTEXT *MachoContext;
610
611 UINT64 TargetAddress;
612 MACH_NLIST_ANY *Symbol;
613 CONST CHAR8 *Name;
614 MACH_SECTION_ANY *Section;
615 UINT64 PairAddress;
616 UINT64 PairDummy;
617
618 ASSERT (Target != NULL);
619 ASSERT (PairTarget != NULL);
620
621 MachoContext = &Kext->Context.MachContext;
622
623 PairAddress = 0;
624 //
625 // Pull out the data from the relocation entries. The target_type depends
626 // on the Extern bit:
627 // Scattered -> Section Lookup by Address.
628 // Local (not extern) -> Section by Index
629 // Extern -> Symbolnum by Index
630 //
631 // Relocations referencing a symbol result in a Target of its resolved value.
632 // Relocations referencing a section result in a Target of
633 // (link_addr - base_addr), which should be LoadAddress aligned on the
634 // section's boundary.
635 //
636 if (Relocation->Extern != 0) {
637 Symbol = MachoGetSymbolByIndex (
638 MachoContext,
639 Relocation->SymbolNumber
640 );
641 if (Symbol == NULL) {
642 return FALSE;
643 }
644
645 Name = MachoGetSymbolName (MachoContext, Symbol);
646 //
647 // If this symbol is a padslot that has already been replaced, then the
648 // only way a relocation entry can still reference it is if there is a
649 // vtable that has not been patched. The vtable patcher uses the
650 // MetaClass structure to find classes for patching, so an unpatched
651 // vtable means that there is an OSObject-dervied class that is missing
652 // its OSDeclare/OSDefine macros.
653 // - FIXME: This cannot currently be checked with the means of this
654 // library. KXLD creates copies of patched VTable symbols, marks
655 // the originals patched and then updates the referencing reloc.
656 //
657
658 if ((Vtable != NULL) && MachoSymbolNameIsVtable (Name)) {
659 *Vtable = InternalGetOcVtableByName (Context, Kext, Name);
660 }
661
662 TargetAddress = Context->Is32Bit ? Symbol->Symbol32.Value : Symbol->Symbol64.Value;
663 if (TargetAddress == 0) {
664 DEBUG ((DEBUG_INFO, "OCAK: Symbol %a has 0-value\n", Name));
665 }
666 } else {
667 if ( (Relocation->SymbolNumber == NO_SECT)
668 || (Relocation->SymbolNumber > MAX_SECT))
669 {
670 return FALSE;
671 }
672
673 Section = MachoGetSectionByIndex (
674 MachoContext,
675 (Relocation->SymbolNumber - 1)
676 );
677 if (Section == NULL) {
678 return FALSE;
679 }
680
681 if (Context->Is32Bit) {
682 TargetAddress = ALIGN_VALUE (
683 (Section->Section32.Address + LoadAddress),
684 LShiftU64 (1, Section->Section32.Alignment)
685 );
686 TargetAddress -= Section->Section32.Address;
687 } else {
688 TargetAddress = ALIGN_VALUE (
689 (Section->Section64.Address + LoadAddress),
690 LShiftU64 (1, Section->Section64.Alignment)
691 );
692 TargetAddress -= Section->Section64.Address;
693 }
694 }
695
696 if (Context->Is32Bit ?
697 MachoRelocationIsPairIntel32 ((UINT8)Relocation->Type) :
698 MachoRelocationIsPairIntel64 ((UINT8)Relocation->Type)
699 )
700 {
701 if (NextRelocation == NULL) {
702 return FALSE;
703 }
704
705 //
706 // As this relocation is the second one in a pair, it cannot be the start
707 // of a pair itself. Pass dummy data for the related arguments. This call
708 // shall never reach this very branch.
709 //
710 Success = InternalCalculateTargets (
711 Context,
712 Kext,
713 LoadAddress,
714 NextRelocation,
715 NULL,
716 &PairAddress,
717 &PairDummy,
718 NULL
719 );
720 if (!Success) {
721 return FALSE;
722 }
723 }
724
725 *Target = TargetAddress;
726 *PairTarget = PairAddress;
727
728 return TRUE;
729}
730
739STATIC
740BOOLEAN
742 IN BOOLEAN Is32Bit,
743 IN CONST PRELINKED_VTABLE *Vtable,
744 IN UINT64 Offset
745 )
746{
747 UINT32 Remainder;
748 UINT64 Index;
749 CONST PRELINKED_VTABLE_ENTRY *Entry;
750
751 DivU64x32Remainder (Offset, Is32Bit ? sizeof (UINT32) : sizeof (UINT64), &Remainder);
752 if ((Remainder != 0) || (Offset < VTABLE_ENTRY_SIZE_X (Is32Bit))) {
753 return FALSE;
754 }
755
756 Index = DivU64x32 (Offset - VTABLE_ENTRY_SIZE_X (Is32Bit), Is32Bit ? sizeof (UINT32) : sizeof (UINT64));
757 if (Index >= Vtable->NumEntries) {
758 return FALSE;
759 }
760
761 Entry = &Vtable->Entries[Index];
762 if (Entry->Name == NULL) {
763 return FALSE;
764 }
765
766 return MachoSymbolNameIsPureVirtual (Entry->Name);
767}
768
791STATIC
792UINTN
794 IN PRELINKED_CONTEXT *Context,
795 IN PRELINKED_KEXT *Kext,
796 IN UINT64 LoadAddress,
797 IN UINT64 RelocationBase,
798 IN CONST MACH_RELOCATION_INFO *Relocation,
799 IN CONST MACH_RELOCATION_INFO *NextRelocation OPTIONAL
800 )
801{
802 UINTN ReturnValue;
803
804 UINT8 Type;
805 INT32 Instruction32;
806 UINT64 Instruction64;
807 UINT64 Target;
808 BOOLEAN IsPair;
809 UINT64 PairTarget;
810 CONST PRELINKED_VTABLE *Vtable;
811 UINT64 LinkPc;
812 UINT64 Adjustment;
813 UINT32 Length;
814 UINT32 Address;
815 UINT8 *InstructionPtr;
816 UINT32 MaxSize;
817 BOOLEAN PcRelative;
818 BOOLEAN IsNormalLocal;
819 BOOLEAN Result;
820 BOOLEAN InvalidPcRel;
821
822 MACH_SCATTERED_RELOCATION_INFO *ScatteredRelocation;
823
824 ASSERT (Relocation != NULL);
825
826 IsPair = FALSE;
827 Adjustment = 0;
828 IsNormalLocal = FALSE;
829
830 Address = Relocation->Address;
831 Length = Relocation->Size;
832 Type = (UINT8)Relocation->Type;
833 PcRelative = (Relocation->PcRelative != 0);
834 PairTarget = 0;
835
836 InvalidPcRel = FALSE;
837 ScatteredRelocation = NULL;
838
839 //
840 // Scattered relocations apply only to 32-bit.
841 //
842 if (Context->Is32Bit) {
843 if (((MACH_SCATTERED_RELOCATION_INFO *)Relocation)->Scattered) {
844 ScatteredRelocation = (MACH_SCATTERED_RELOCATION_INFO *)Relocation;
845
846 Address = ScatteredRelocation->Address;
847 Length = ScatteredRelocation->Size;
848 Type = (UINT8)ScatteredRelocation->Type;
849 PcRelative = (ScatteredRelocation->PcRelative != 0);
850 Target = LoadAddress;
851 }
852 }
853
854 if (Length < 2) {
855 return MAX_UINTN;
856 }
857
858 InstructionPtr = MachoGetFilePointerByAddress (
859 &Kext->Context.MachContext,
860 (RelocationBase + Address),
861 &MaxSize
862 );
863 if ((InstructionPtr == NULL) || (MaxSize < ((Length != 3) ? 4U : 8U))) {
864 return MAX_UINTN;
865 }
866
867 if (Relocation->Extern == 0) {
868 IsNormalLocal = TRUE;
869 }
870
871 LinkPc = (Address + LoadAddress);
872
873 Vtable = NULL;
874 if (ScatteredRelocation == NULL) {
875 Result = InternalCalculateTargets (
876 Context,
877 Kext,
878 LoadAddress,
879 Relocation,
880 NextRelocation,
881 &Target,
882 &PairTarget,
883 &Vtable
884 );
885 if (!Result) {
886 return MAX_UINTN;
887 }
888 }
889
890 //
891 // Length == 2
892 //
893 if (Length != 3) {
894 CopyMem (&Instruction32, InstructionPtr, sizeof (Instruction32));
895
896 if ( (Vtable != NULL)
897 && InternalIsDirectPureVirtualCall (Context->Is32Bit, Vtable, Instruction32))
898 {
899 return MAX_UINTN;
900 }
901
902 if (Context->Is32Bit) {
903 if (PcRelative) {
904 Target = Target + Address - (LinkPc + RelocationBase);
905 }
906
907 switch (Type) {
909 Instruction32 += (UINT32)Target;
910 break;
911
912 default:
913 DEBUG ((DEBUG_ERROR, "OCAK: Non-vanilla 32-bit relocations are unsupported\n")); // FIXME: Implement paired relocs.
914 return MAX_UINTN;
915 }
916 } else {
917 //
918 // There are a number of different small adjustments for pc-relative
919 // relocation entries. The general case is to subtract the size of the
920 // relocation (represented by the length parameter), and it applies to
921 // the GOT types and external SIGNED types. The non-external signed types
922 // have a different adjustment corresponding to the specific type.
923 //
924 switch (Type) {
926 if (IsNormalLocal) {
927 Adjustment = 0;
928 break;
929 }
930
931 // Fall through
933 if (IsNormalLocal) {
934 Adjustment = 1;
935 break;
936 }
937
938 // Fall through
940 if (IsNormalLocal) {
941 Adjustment = 2;
942 break;
943 }
944
945 // Fall through
947 if (IsNormalLocal) {
948 Adjustment = 4;
949 break;
950 }
951
952 // Fall through
956 {
957 Adjustment = LShiftU64 (1, Length);
958 break;
959 }
960
961 default:
962 {
963 break;
964 }
965 }
966
967 //
968 // Perform the actual relocation. All of the 32-bit relocations are
969 // pc-relative except for SUBTRACTOR, so a good chunk of the logic is
970 // stuck in calculate_displacement_x86_64. The signed relocations are
971 // a special case, because when they are non-external, the instruction
972 // already contains the pre-relocation displacement, so we only need to
973 // find the difference between how far the PC was relocated, and how
974 // far the target is relocated. Since the target variable already
975 // contains the difference between the target's base and link
976 // addresses, we add the difference between the PC's base and link
977 // addresses to the adjustment variable. This will yield the
978 // appropriate displacement in calculate_displacement.
979 //
980 switch (Type) {
982 {
983 InvalidPcRel = !PcRelative;
984 Adjustment += LinkPc;
985 break;
986 }
987
992 {
993 InvalidPcRel = !PcRelative;
994 Adjustment += (IsNormalLocal ? LoadAddress : LinkPc);
995 break;
996 }
997
1000 {
1001 InvalidPcRel = !PcRelative;
1002 Adjustment += LinkPc;
1003 Target = PairTarget;
1004 IsPair = TRUE;
1005 break;
1006 }
1007
1009 {
1010 InvalidPcRel = PcRelative;
1011 Instruction32 = (INT32)(Target - PairTarget);
1012 IsPair = TRUE;
1013 break;
1014 }
1015
1016 default:
1017 {
1018 return MAX_UINTN;
1019 }
1020 }
1021
1022 if (PcRelative) {
1024 Target,
1025 Adjustment,
1026 &Instruction32
1027 );
1028 if (!Result) {
1029 return MAX_UINTN;
1030 }
1031 }
1032 }
1033
1034 CopyMem (InstructionPtr, &Instruction32, sizeof (Instruction32));
1035 } else {
1036 CopyMem (&Instruction64, InstructionPtr, sizeof (Instruction64));
1037
1038 if ( (Vtable != NULL)
1039 && InternalIsDirectPureVirtualCall (Context->Is32Bit, Vtable, Instruction64))
1040 {
1041 return MAX_UINTN;
1042 }
1043
1044 switch (Type) {
1046 {
1047 InvalidPcRel = PcRelative;
1048 Instruction64 += Target;
1049 break;
1050 }
1051
1053 {
1054 InvalidPcRel = PcRelative;
1055 Instruction64 = (Target - PairTarget);
1056 IsPair = TRUE;
1057 break;
1058 }
1059
1060 default:
1061 {
1062 return MAX_UINTN;
1063 }
1064 }
1065
1066 CopyMem (InstructionPtr, &Instruction64, sizeof (Instruction64));
1067 }
1068
1069 if (InvalidPcRel) {
1070 DEBUG ((DEBUG_WARN, "OCAK: Relocation has invalid PC relative flag\n"));
1071 }
1072
1073 if (Context->Is32Bit) {
1074 ReturnValue = 0;
1075 } else {
1076 ReturnValue = (MachoPreserveRelocationIntel64 (Type) ? 1 : 0);
1077 }
1078
1079 if (IsPair) {
1080 ReturnValue |= BIT31;
1081 }
1082
1083 return ReturnValue;
1084}
1085
1104STATIC
1105BOOLEAN
1107 IN PRELINKED_CONTEXT *Context,
1108 IN PRELINKED_KEXT *Kext,
1109 IN UINT64 LoadAddress,
1110 IN UINT64 RelocationBase,
1111 IN CONST MACH_RELOCATION_INFO *SourceRelocations,
1112 IN OUT UINT32 *NumRelocations,
1113 OUT MACH_RELOCATION_INFO *TargetRelocations
1114 )
1115{
1116 UINT32 PreservedRelocations;
1117
1118 UINT32 Index;
1119 UINT32 SectionIndex;
1120 CONST MACH_RELOCATION_INFO *NextRelocation;
1121 UINTN Result;
1122 MACH_RELOCATION_INFO *Relocation;
1123 MACH_SECTION *Section32;
1124
1125 ASSERT (Kext != NULL);
1126 ASSERT (NumRelocations != NULL);
1127 ASSERT (SourceRelocations != NULL || *NumRelocations == 0);
1128
1129 //
1130 // Fallback to section-based relocations if needed for 32-bit.
1131 //
1132 if (Context->Is32Bit && (*NumRelocations == 0)) {
1133 SectionIndex = 0;
1134 while (TRUE) {
1135 Section32 = MachoGetSectionByIndex32 (&Kext->Context.MachContext, SectionIndex);
1136 if (Section32 == NULL) {
1137 break;
1138 }
1139
1140 if (Section32->NumRelocations > 0) {
1141 Relocation = (MACH_RELOCATION_INFO *)((UINTN)MachoGetFileData (&Kext->Context.MachContext) + Section32->RelocationsOffset);
1142 for (Index = 0; Index < Section32->NumRelocations; ++Index) {
1143 NextRelocation = &Relocation[Index + 1];
1144 //
1145 // The last Relocation does not have a successor.
1146 //
1147 if (Index == (Section32->NumRelocations - 1)) {
1148 NextRelocation = NULL;
1149 }
1150
1151 //
1152 // Relocate the relocation.
1153 //
1155 Context,
1156 Kext,
1157 LoadAddress,
1158 RelocationBase + Section32->Address,
1159 &Relocation[Index],
1160 NextRelocation
1161 );
1162 if (Result == MAX_UINTN) {
1163 return FALSE;
1164 }
1165 }
1166
1167 Section32->NumRelocations = 0;
1168 Section32->RelocationsOffset = 0;
1169 }
1170
1171 ++SectionIndex;
1172 }
1173
1174 return TRUE;
1175 }
1176
1177 ASSERT (TargetRelocations != NULL);
1178
1179 PreservedRelocations = 0;
1180
1181 for (Index = 0; Index < *NumRelocations; ++Index) {
1182 //
1183 // Assertion: Not i386. Scattered Relocations are only supported by i386.
1184 // && ((UINT32)Relocation->Address & MACH_RELOC_SCATTERED) == 0
1185 //
1186 if ( (SourceRelocations[Index].Extern == 0)
1187 && (SourceRelocations[Index].SymbolNumber == MACH_RELOC_ABSOLUTE))
1188 {
1189 //
1190 // A section-based relocation entry can be skipped for absolute
1191 // symbols.
1192 //
1193 continue;
1194 }
1195
1196 NextRelocation = &SourceRelocations[Index + 1];
1197 //
1198 // The last Relocation does not have a successor.
1199 //
1200 if (Index == (*NumRelocations - 1)) {
1201 NextRelocation = NULL;
1202 }
1203
1204 //
1205 // Relocate the relocation.
1206 //
1208 Context,
1209 Kext,
1210 LoadAddress,
1211 RelocationBase,
1212 &SourceRelocations[Index],
1213 NextRelocation
1214 );
1215 if (Result == MAX_UINTN) {
1216 return FALSE;
1217 }
1218
1219 //
1220 // Copy the Relocation to the destination buffer if it shall be preserved.
1221 //
1222 if ((Result & ~(UINTN)BIT31) != 0) {
1223 Relocation = &TargetRelocations[PreservedRelocations];
1224
1225 CopyMem (Relocation, &SourceRelocations[Index], sizeof (*Relocation));
1226
1227 if (Relocation->Extern != 0) {
1228 //
1229 // All relocation targets have been updated with symbol values.
1230 // Convert to a local relocation as only sliding is supported from now
1231 // on.
1232 //
1233 Relocation->Extern = 0;
1234 //
1235 // Assertion: The entire kext will be slid by the same offset.
1236 // This is asserted by KXLD as well.
1237 //
1238 Relocation->SymbolNumber = 1;
1239 }
1240
1241 ++PreservedRelocations;
1242 }
1243
1244 //
1245 // Skip the next Relocation as instructed by
1246 // InternalRelocateRelocation().
1247 //
1248 if ((Result & BIT31) != 0) {
1249 ++Index;
1250 }
1251 }
1252
1253 *NumRelocations = PreservedRelocations;
1254
1255 return TRUE;
1256}
1257
1258//
1259// MACH header
1260//
1261
1262STATIC
1263BOOLEAN
1265 IN OC_MACHO_CONTEXT *MachoContext,
1266 IN UINT64 LoadAddress,
1267 IN OUT MACH_NLIST_ANY *Symbol,
1268 IN OUT UINT32 *KmodInfoOffset
1269 )
1270{
1271 BOOLEAN Result;
1272 CONST CHAR8 *SymbolName;
1273 UINT32 KmodOffset;
1274 UINT32 MaxSize;
1275
1276 KmodOffset = *KmodInfoOffset;
1277
1278 if ((KmodOffset == 0) && (((MachoContext->Is32Bit ? Symbol->Symbol32.Type : Symbol->Symbol64.Type) & MACH_N_TYPE_STAB) == 0)) {
1279 SymbolName = MachoGetSymbolName (MachoContext, Symbol);
1280 ASSERT (SymbolName != NULL);
1281
1282 if (AsciiStrCmp (SymbolName, "_kmod_info") == 0) {
1283 Result = MachoSymbolGetFileOffset (
1284 MachoContext,
1285 Symbol,
1286 &KmodOffset,
1287 &MaxSize
1288 );
1289 if ( !Result
1290 || ( (MaxSize < (MachoContext->Is32Bit ? sizeof (KMOD_INFO_32_V1) : sizeof (KMOD_INFO_64_V1)))
1291 || ((KmodOffset % 4) != 0)))
1292 {
1293 return FALSE;
1294 }
1295
1296 *KmodInfoOffset = KmodOffset;
1297 }
1298 }
1299
1300 return MachoRelocateSymbol (
1301 MachoContext,
1302 LoadAddress,
1303 Symbol
1304 );
1305}
1306
1307STATIC
1308BOOLEAN
1310 IN OC_MACHO_CONTEXT *MachoContext,
1311 IN UINT64 LoadAddress,
1312 IN UINT32 NumSymbols,
1313 IN OUT MACH_NLIST_ANY *Symbols,
1314 OUT UINT32 *KmodInfoOffset
1315 )
1316{
1317 BOOLEAN Result;
1318 UINT32 Index;
1319 MACH_NLIST_ANY *Symbol;
1320 UINT8 SymbolType;
1321
1322 ASSERT (MachoContext != NULL);
1323 ASSERT (Symbols != NULL || NumSymbols == 0);
1324 ASSERT (KmodInfoOffset != NULL);
1325
1326 //
1327 // Fallback to standard symbol lookup if needed for 32-bit.
1328 //
1329 if (MachoContext->Is32Bit && (NumSymbols == 0)) {
1330 Index = 0;
1331 while (TRUE) {
1332 Symbol = MachoGetSymbolByIndex (MachoContext, Index);
1333 if (Symbol == NULL) {
1334 break;
1335 }
1336
1337 SymbolType = Symbol->Symbol32.Type & MACH_N_TYPE_TYPE;
1338 if ((SymbolType == MACH_N_TYPE_SECT) || (SymbolType == MACH_N_TYPE_EXT)) {
1339 Result = InternalRelocateSymbol (
1340 MachoContext,
1341 LoadAddress,
1342 Symbol,
1343 KmodInfoOffset
1344 );
1345
1346 if (!Result) {
1347 return FALSE;
1348 }
1349 }
1350
1351 ++Index;
1352 }
1353
1354 return TRUE;
1355 }
1356
1357 for (Index = 0; Index < NumSymbols; ++Index) {
1358 if (MachoContext->Is32Bit) {
1359 Symbol = (MACH_NLIST_ANY *)&(&Symbols->Symbol32)[Index];
1360 } else {
1361 Symbol = (MACH_NLIST_ANY *)&(&Symbols->Symbol64)[Index];
1362 }
1363
1364 Result = InternalRelocateSymbol (
1365 MachoContext,
1366 LoadAddress,
1367 Symbol,
1368 KmodInfoOffset
1369 );
1370
1371 if (!Result) {
1372 return FALSE;
1373 }
1374 }
1375
1376 return TRUE;
1377}
1378
1382STATIC
1383BOOLEAN
1385 IN OC_MACHO_CONTEXT *MachoContext,
1386 IN CONST MACH_DYSYMTAB_COMMAND *DySymtab,
1387 IN UINT64 LoadAddress
1388 )
1389{
1390 CONST VOID *FileData;
1391 UINT32 MachSize;
1392 CONST MACH_SECTION_ANY *Section;
1393 UINT32 NumSymbols;
1394 UINT32 FirstSym;
1395 BOOLEAN Result;
1396 UINT32 OffsetTop;
1397 CONST UINT32 *SymIndices;
1398 VOID *IndirectSymPtr;
1399 UINT32 Index;
1400 CONST MACH_NLIST_ANY *Symbol;
1401
1402 VOID *Tmp;
1403
1405 MachoContext,
1406 "__DATA",
1407 "__nl_symbol_ptr"
1408 );
1409 if (Section == NULL) {
1410 return TRUE;
1411 }
1412
1413 if (MachoContext->Is32Bit) {
1414 NumSymbols = Section->Section32.Size / sizeof (UINT32);
1415 FirstSym = Section->Section32.Reserved1;
1416 } else {
1417 NumSymbols = (UINT32)(Section->Section64.Size / sizeof (UINT64));
1418 FirstSym = Section->Section64.Reserved1;
1419 }
1420
1421 Result = BaseOverflowAddU32 (FirstSym, NumSymbols, &OffsetTop);
1422 if (Result || (OffsetTop > DySymtab->NumIndirectSymbols)) {
1423 return FALSE;
1424 }
1425
1426 MachSize = MachoGetFileSize (MachoContext);
1427 Result = BaseOverflowMulAddU32 (
1428 DySymtab->NumIndirectSymbols,
1429 MachoContext->Is32Bit ? sizeof (UINT32) : sizeof (UINT64),
1430 DySymtab->IndirectSymbolsOffset,
1431 &OffsetTop
1432 );
1433 if (Result || (OffsetTop > MachSize)) {
1434 return FALSE;
1435 }
1436
1437 FileData = MachoGetMachHeader (MachoContext);
1438 ASSERT (FileData != NULL);
1439 //
1440 // Iterate through the indirect symbol table and fill in the section of
1441 // symbol pointers. There are three cases:
1442 // 1) A normal symbol - put its value directly in the table
1443 // 2) An INDIRECT_SYMBOL_LOCAL - symbols that are local and already have
1444 // their offset from the start of the file in the section. Simply
1445 // add the file's link address to fill this entry.
1446 // 3) An INDIRECT_SYMBOL_ABS - prepopulated absolute symbols. No
1447 // action is required.
1448 //
1449 Tmp = (VOID *)((UINTN)FileData + DySymtab->IndirectSymbolsOffset);
1450 if (!BASE_TYPE_ALIGNED (UINT32, Tmp)) {
1451 return FALSE;
1452 }
1453
1454 SymIndices = (UINT32 *)Tmp + FirstSym;
1455
1456 IndirectSymPtr = (VOID *)((UINTN)FileData + (MachoContext->Is32Bit ? Section->Section32.Offset : Section->Section64.Offset));
1457 if (MachoContext->Is32Bit ? !BASE_TYPE_ALIGNED (UINT32, IndirectSymPtr) : !BASE_TYPE_ALIGNED (UINT64, IndirectSymPtr)) {
1458 return FALSE;
1459 }
1460
1461 for (Index = 0; Index < NumSymbols; ++Index) {
1462 if ((SymIndices[Index] & MACH_INDIRECT_SYMBOL_LOCAL) != 0) {
1463 if ((SymIndices[Index] & MACH_INDIRECT_SYMBOL_ABS) != 0) {
1464 continue;
1465 }
1466
1467 if (MachoContext->Is32Bit) {
1468 ((UINT32 *)IndirectSymPtr)[Index] += (UINT32)LoadAddress;
1469 } else {
1470 ((UINT64 *)IndirectSymPtr)[Index] += LoadAddress;
1471 }
1472 } else {
1473 Symbol = MachoGetSymbolByIndex (MachoContext, SymIndices[Index]);
1474 if (Symbol == NULL) {
1475 return FALSE;
1476 }
1477
1478 if (MachoContext->Is32Bit) {
1479 ((UINT32 *)IndirectSymPtr)[Index] += Symbol->Symbol32.Value;
1480 } else {
1481 ((UINT64 *)IndirectSymPtr)[Index] += Symbol->Symbol64.Value;
1482 }
1483 }
1484 }
1485
1486 return TRUE;
1487}
1488
1502EFI_STATUS
1504 IN OUT PRELINKED_CONTEXT *Context,
1505 IN PRELINKED_KEXT *Kext,
1506 IN UINT64 LoadAddress,
1507 IN UINT64 FileOffset
1508 )
1509{
1510 OC_MACHO_CONTEXT *MachoContext;
1511 MACH_SEGMENT_COMMAND_ANY *LinkEditSegment;
1512 UINT64 LinkEditFileOffset;
1513 UINT64 LinkEditFileSize;
1514
1515 VOID *FileData;
1516 MACH_HEADER_ANY *MachHeader;
1517 UINT32 MachSize;
1518 BOOLEAN IsObject32;
1519
1520 MACH_SEGMENT_COMMAND_ANY *Segment;
1521 MACH_SECTION_ANY *Section;
1522
1523 UINT32 Index;
1524 BOOLEAN Result;
1525 UINT32 SymtabSize;
1526 UINT32 SymtabSize2;
1527
1528 MACH_SYMTAB_COMMAND *Symtab;
1529 MACH_DYSYMTAB_COMMAND *DySymtab;
1530 MACH_NLIST_ANY *Symbol;
1531 CONST CHAR8 *SymbolName;
1532 CONST MACH_NLIST_ANY *SymbolTable;
1533 CONST CHAR8 *StringTable;
1534 UINT32 NumSymbols;
1535 CONST MACH_NLIST_ANY *IndirectSymtab;
1536 UINT32 NumIndirectSymbols;
1537 CONST MACH_NLIST_ANY *LocalSymtab;
1538 UINT32 NumLocalSymbols;
1539 CONST MACH_NLIST_ANY *ExternalSymtab;
1540 UINT32 NumExternalSymbols;
1541 CONST MACH_NLIST_ANY *UndefinedSymtab;
1542 UINT32 NumUndefinedSymbols;
1543 UINT64 WeakTestValue;
1544
1545 UINT32 NumRelocations;
1546 UINT32 NumRelocations2;
1547 CONST MACH_RELOCATION_INFO *Relocations;
1548 MACH_RELOCATION_INFO *TargetRelocation;
1549 MACH_SEGMENT_COMMAND_ANY *FirstSegment;
1550
1551 VOID *LinkEdit;
1552 UINT32 LinkEditSize;
1553 UINT32 SymbolTableOffset;
1554 UINT32 SymbolTableSize;
1555 UINT32 RelocationsOffset;
1556 UINT32 RelocationsSize;
1557 UINT32 StringTableOffset;
1558 UINT32 StringTableSize;
1559 MACH_NLIST *SymtabLinkEdit32;
1560 UINT32 NumSymtabLinkEdit32Symbols;
1561
1562 UINT32 SegmentOffset;
1563 UINT32 SegmentSize;
1564 UINT64 LoadAddressOffset;
1565
1566 UINT64 SegmentVmSizes;
1567 UINT32 KmodInfoOffset;
1568 KMOD_INFO_ANY *KmodInfo;
1569
1570 ASSERT (Context != NULL);
1571 ASSERT (Kext != NULL);
1572 ASSERT (LoadAddress != 0);
1573
1574 //
1575 // ASSUMPTIONS:
1576 // If kext is 64-bit, it has a __LINKEDIT segment and DYSYMTAB.
1577 // If kext is 32-bit, it has a __LINKEDIT segment and DYSYMTAB if its not MH_OBJECT.
1578 //
1579
1580 MachoContext = &Kext->Context.MachContext;
1581 LinkEditSegment = Kext->LinkEditSegment;
1582
1583 //
1584 // Kexts cannot be contained.
1585 //
1586 ASSERT ((VOID *)MachoGetMachHeader (MachoContext) == MachoGetFileData (MachoContext));
1587 ASSERT (MachoGetInnerSize (MachoContext) == MachoGetFileSize (MachoContext));
1588
1589 MachHeader = MachoGetMachHeader (MachoContext);
1590 MachSize = MachoGetFileSize (MachoContext);
1591
1592 FileData = (VOID *)MachHeader;
1593
1594 IsObject32 = Context->Is32Bit && MachHeader->Header32.FileType == MachHeaderFileTypeObject;
1595
1596 //
1597 // Only perform actions when the kext is flag'd to be dynamically linked.
1598 //
1599 if ( !IsObject32
1600 && (((Context->Is32Bit ? MachHeader->Header32.Flags : MachHeader->Header64.Flags) & MACH_HEADER_FLAG_DYNAMIC_LINKER_LINK) == 0))
1601 {
1602 return EFI_SUCCESS;
1603 }
1604
1605 if ((!IsObject32 && (LinkEditSegment == NULL)) || (Kext->Context.VirtualKmod == 0)) {
1606 return EFI_UNSUPPORTED;
1607 }
1608
1609 if (BaseOverflowAddU64 (LoadAddress, FileOffset, &LoadAddressOffset)) {
1610 return EFI_INVALID_PARAMETER;
1611 }
1612
1613 if (Context->Is32Bit) {
1614 ASSERT (LoadAddressOffset < MAX_UINT32);
1615 }
1616
1617 //
1618 // Retrieve the symbol tables required for most following operations.
1619 //
1620 NumSymbols = MachoGetSymbolTable (
1621 MachoContext,
1622 &SymbolTable,
1623 &StringTable,
1624 &LocalSymtab,
1625 &NumLocalSymbols,
1626 &ExternalSymtab,
1627 &NumExternalSymbols,
1628 &UndefinedSymtab,
1629 &NumUndefinedSymbols
1630 );
1631 if (NumSymbols == 0) {
1632 return EFI_UNSUPPORTED;
1633 }
1634
1635 Symtab = MachoContext->Symtab;
1636 ASSERT (Symtab != NULL);
1637
1638 DySymtab = MachoContext->DySymtab;
1639 if (!IsObject32) {
1640 ASSERT (DySymtab != NULL);
1641 }
1642
1643 //
1644 // Prepare constructing a new __LINKEDIT section to...
1645 // 1. strip undefined symbols for they are not allowed in prelinked
1646 // binaries,
1647 // 2. merge local and external relocations as only sliding is allowed from
1648 // this point onwards,
1649 // 3. strip Code Signature because we modified the binary, as well as other
1650 // linker metadata stripped by KXLD as well, probably for space reasons.
1651 //
1652 // Example original layout:
1653 // Local relocations - Symbol Table - external relocations - String Table -
1654 // Code Signature
1655 //
1656 // Example prelinked layout
1657 // Symbol Table - relocations (external -> local) - String Table
1658 //
1659 SymbolTableSize = (NumSymbols * (Context->Is32Bit ? sizeof (MACH_NLIST) : sizeof (MACH_NLIST_64)));
1660 StringTableSize = Symtab->StringsSize;
1661
1662 //
1663 // For the allocation, assume all relocations will be preserved to simplify
1664 // the code, the memory is only temporarily allocated anyway.
1665 //
1666 if (!IsObject32) {
1667 NumRelocations = DySymtab->NumOfLocalRelocations;
1668 NumRelocations += DySymtab->NumExternalRelocations;
1669 } else {
1670 NumRelocations = 0;
1671 }
1672
1673 RelocationsSize = (NumRelocations * sizeof (MACH_RELOCATION_INFO));
1674
1675 LinkEdit = Context->LinkBuffer;
1676 LinkEditSize = (SymbolTableSize + RelocationsSize + StringTableSize);
1677
1678 if ( !IsObject32
1679 && (LinkEditSize > (Context->Is32Bit ? LinkEditSegment->Segment32.FileSize : LinkEditSegment->Segment64.FileSize)))
1680 {
1681 return EFI_UNSUPPORTED;
1682 }
1683
1684 SymbolTableSize -= (NumUndefinedSymbols * (Context->Is32Bit ? sizeof (MACH_NLIST) : sizeof (MACH_NLIST_64)));
1685
1686 SymbolTableOffset = 0;
1687 RelocationsOffset = (SymbolTableOffset + SymbolTableSize);
1688
1689 //
1690 // Solve indirect symbols.
1691 // For 32-bit objects, we will solve those at the same time as undefined symbols later.
1692 //
1693 if (!IsObject32) {
1694 WeakTestValue = 0;
1695 NumIndirectSymbols = MachoGetIndirectSymbolTable (
1696 MachoContext,
1697 &IndirectSymtab
1698 );
1699 for (Index = 0; Index < NumIndirectSymbols; ++Index) {
1700 Symbol = (MACH_NLIST_ANY *)&IndirectSymtab[Index];
1701 SymbolName = MachoGetIndirectSymbolName (MachoContext, Symbol);
1702 if (SymbolName == NULL) {
1703 return EFI_LOAD_ERROR;
1704 }
1705
1706 Result = InternalSolveSymbol (
1707 Context,
1708 Kext,
1709 SymbolName,
1710 Symbol,
1711 &WeakTestValue,
1712 UndefinedSymtab,
1713 NumUndefinedSymbols
1714 );
1715 if (!Result) {
1716 return EFI_LOAD_ERROR;
1717 }
1718 }
1719 }
1720
1721 //
1722 // Solve undefined symbols. If on 32-bit, we may not have a DYSYMTAB so fallback to checking all symbols.
1723 // All non-undefined symbols will have their indexes stored in the new symtab in LinkBuffer for later use.
1724 //
1725 NumSymtabLinkEdit32Symbols = 0;
1726 if (IsObject32) {
1727 NumUndefinedSymbols = NumSymbols;
1728 }
1729
1730 for (Index = 0; Index < NumUndefinedSymbols; ++Index) {
1731 if (Context->Is32Bit) {
1732 Symbol = (MACH_NLIST_ANY *)(!IsObject32 ? &(&UndefinedSymtab->Symbol32)[Index] : &(&SymbolTable->Symbol32)[Index]);
1733 if ( IsObject32
1735 && ((Symbol->Symbol32.Type & MACH_N_TYPE_TYPE) != MACH_N_TYPE_INDR))
1736 {
1737 continue;
1738 }
1739 } else {
1740 Symbol = (MACH_NLIST_ANY *)&(&UndefinedSymtab->Symbol64)[Index];
1741 }
1742
1743 //
1744 // Undefined symbols are solved via their name.
1745 //
1746 SymbolName = MachoGetSymbolName (MachoContext, Symbol);
1747 Result = InternalSolveSymbol (
1748 Context,
1749 Kext,
1750 SymbolName,
1751 Symbol,
1752 &WeakTestValue,
1753 !IsObject32 ? UndefinedSymtab : NULL,
1754 !IsObject32 ? NumUndefinedSymbols : 0
1755 );
1756 if (!Result) {
1757 DEBUG ((
1758 DEBUG_INFO,
1759 "OCAK: Symbol %a was unresolved for kext %a\n",
1760 MachoGetSymbolName (MachoContext, Symbol),
1761 Kext->Identifier
1762 ));
1763 return EFI_LOAD_ERROR;
1764 } else {
1765 DEBUG ((
1766 DEBUG_VERBOSE,
1767 "OCAK: Symbol %a was resolved for kext %a to %Lx\n",
1768 MachoGetSymbolName (MachoContext, Symbol),
1769 Kext->Identifier,
1770 Context->Is32Bit ? Symbol->Symbol32.Value : Symbol->Symbol64.Value
1771 ));
1772 }
1773 }
1774
1775 //
1776 // Create and patch the KEXT's VTables.
1777 //
1778 Result = InternalPatchByVtables (Context, Kext);
1779 if (!Result) {
1780 DEBUG ((DEBUG_INFO, "OCAK: Vtable patching failed for kext %a\n", Kext->Identifier));
1781 return EFI_LOAD_ERROR;
1782 }
1783
1784 //
1785 // Relocate local and external symbols.
1786 // We only need to call InternalRelocateSymbols once if there is no DYSYMTAB.
1787 //
1788 KmodInfoOffset = 0;
1789 if (!IsObject32) {
1790 Result = InternalRelocateSymbols (
1791 MachoContext,
1792 LoadAddressOffset,
1793 NumLocalSymbols,
1794 (MACH_NLIST_ANY *)LocalSymtab,
1795 &KmodInfoOffset
1796 );
1797 if (!Result) {
1798 return EFI_LOAD_ERROR;
1799 }
1800 }
1801
1802 Result = InternalRelocateSymbols (
1803 MachoContext,
1804 LoadAddressOffset,
1805 NumExternalSymbols,
1806 (MACH_NLIST_ANY *)ExternalSymtab,
1807 &KmodInfoOffset
1808 );
1809 if (!Result || (KmodInfoOffset == 0)) {
1810 return EFI_LOAD_ERROR;
1811 }
1812
1813 KmodInfo = (KMOD_INFO_ANY *)((UINTN)FileData + (UINTN)KmodInfoOffset);
1814
1815 FirstSegment = MachoGetNextSegment (MachoContext, NULL);
1816 if (FirstSegment == NULL) {
1817 return EFI_UNSUPPORTED;
1818 }
1819
1820 Result = InternalProcessSymbolPointers (MachoContext, DySymtab, LoadAddressOffset);
1821 if (!Result) {
1822 return EFI_LOAD_ERROR;
1823 }
1824
1825 //
1826 // Copy the relocations to be reserved and adapt the symbol number they
1827 // reference in case it has been relocated above.
1828 //
1829 TargetRelocation = (MACH_RELOCATION_INFO *)(
1830 (UINTN)LinkEdit + RelocationsOffset
1831 );
1832
1833 //
1834 // Relocate and copy local and external relocations.
1835 //
1836 Relocations = MachoContext->LocalRelocations;
1837 NumRelocations = !IsObject32 ? DySymtab->NumOfLocalRelocations : 0;
1839 Context,
1840 Kext,
1841 LoadAddressOffset,
1842 Context->Is32Bit ? FirstSegment->Segment32.VirtualAddress : FirstSegment->Segment64.VirtualAddress,
1843 Relocations,
1844 &NumRelocations,
1845 &TargetRelocation[0]
1846 );
1847 if (!Result) {
1848 return EFI_LOAD_ERROR;
1849 }
1850
1851 //
1852 // If there is no DYSYMTAB, the call to InternalRelocateAndCopyRelocations
1853 // above takes care of all relocations.
1854 //
1855 if (!IsObject32) {
1856 Relocations = MachoContext->ExternRelocations;
1857 NumRelocations2 = DySymtab->NumExternalRelocations;
1859 Context,
1860 Kext,
1861 LoadAddressOffset,
1862 Context->Is32Bit ?
1863 FirstSegment->Segment32.VirtualAddress : FirstSegment->Segment64.VirtualAddress,
1864 Relocations,
1865 &NumRelocations2,
1866 &TargetRelocation[NumRelocations]
1867 );
1868 if (!Result) {
1869 return EFI_LOAD_ERROR;
1870 }
1871
1872 NumRelocations += NumRelocations2;
1873 RelocationsSize = (NumRelocations * sizeof (MACH_RELOCATION_INFO));
1874 }
1875
1876 if (!IsObject32) {
1877 //
1878 // Copy the entire symbol table excluding the area for undefined symbols.
1879 //
1880 SymtabSize = SymbolTableSize;
1881 if (NumUndefinedSymbols > 0) {
1882 SymtabSize = (UINT32)((UndefinedSymtab - SymbolTable) * (Context->Is32Bit ? sizeof (MACH_NLIST) : sizeof (MACH_NLIST_64)));
1883 }
1884
1885 CopyMem (
1886 (VOID *)((UINTN)LinkEdit + SymbolTableOffset),
1887 SymbolTable,
1888 SymtabSize
1889 );
1890
1891 if (NumUndefinedSymbols > 0) {
1892 if (Context->Is32Bit) {
1893 SymtabSize2 = (UINT32)(&(&SymbolTable->Symbol32)[NumSymbols] - &(&UndefinedSymtab->Symbol32)[NumUndefinedSymbols]);
1894 SymtabSize2 *= sizeof (MACH_NLIST);
1895
1896 CopyMem (
1897 (VOID *)((UINTN)LinkEdit + SymbolTableOffset + SymtabSize),
1898 (VOID *)&(&UndefinedSymtab->Symbol32)[NumUndefinedSymbols],
1899 SymtabSize2
1900 );
1901 } else {
1902 SymtabSize2 = (UINT32)(&(&SymbolTable->Symbol64)[NumSymbols] - &(&UndefinedSymtab->Symbol64)[NumUndefinedSymbols]);
1903 SymtabSize2 *= sizeof (MACH_NLIST_64);
1904
1905 CopyMem (
1906 (VOID *)((UINTN)LinkEdit + SymbolTableOffset + SymtabSize),
1907 (VOID *)&(&UndefinedSymtab->Symbol64)[NumUndefinedSymbols],
1908 SymtabSize2
1909 );
1910 }
1911
1912 NumSymbols -= NumUndefinedSymbols;
1913 }
1914
1915 //
1916 // Copy the String Table. Don't strip it for the saved bytes are unlikely
1917 // worth the time required.
1918 //
1919 StringTableOffset = (RelocationsOffset + RelocationsSize);
1920 CopyMem (
1921 (VOID *)((UINTN)LinkEdit + StringTableOffset),
1922 StringTable,
1923 StringTableSize
1924 );
1925 //
1926 // Set up the tables with the new offsets and Symbol Table length.
1927 //
1928 if (Context->Is32Bit) {
1929 LinkEditFileOffset = LinkEditSegment->Segment32.FileOffset;
1930 LinkEditFileSize = LinkEditSegment->Segment32.FileSize;
1931 } else {
1932 LinkEditFileOffset = LinkEditSegment->Segment64.FileOffset;
1933 LinkEditFileSize = LinkEditSegment->Segment64.FileSize;
1934 }
1935
1936 Symtab->SymbolsOffset = (UINT32)(LinkEditFileOffset + SymbolTableOffset);
1937 Symtab->NumSymbols = NumSymbols;
1938 Symtab->StringsOffset = (UINT32)(LinkEditFileOffset + StringTableOffset);
1939
1940 //
1941 // Copy the new __LINKEDIT segment into the binary and fix its Load Command.
1942 //
1943 LinkEditSize = (SymbolTableSize + RelocationsSize + StringTableSize);
1944
1945 CopyMem (
1946 (VOID *)((UINTN)FileData + (UINTN)LinkEditFileOffset),
1947 LinkEdit,
1948 LinkEditSize
1949 );
1950 ZeroMem (
1951 (VOID *)((UINTN)FileData + (UINTN)LinkEditFileOffset + LinkEditSize),
1952 (UINTN)(LinkEditFileSize - LinkEditSize)
1953 );
1954
1955 LinkEditSize = MACHO_ALIGN (LinkEditSize);
1956 if (Context->Is32Bit) {
1957 LinkEditSegment->Segment32.FileSize = LinkEditSize;
1958 LinkEditSegment->Segment32.Size = LinkEditSize;
1959 } else {
1960 LinkEditSegment->Segment64.FileSize = LinkEditSize;
1961 LinkEditSegment->Segment64.Size = LinkEditSize;
1962 }
1963
1964 DySymtab->LocalRelocationsOffset = (UINT32)(LinkEditFileOffset + RelocationsOffset);
1965 DySymtab->NumOfLocalRelocations = NumRelocations;
1966
1967 //
1968 // Clear dynamic linker information.
1969 //
1970 DySymtab->LocalSymbolsIndex = 0;
1971 DySymtab->NumLocalSymbols = 0;
1972 DySymtab->NumExternalSymbols = 0;
1973 DySymtab->ExternalSymbolsIndex = 0;
1974 DySymtab->NumExternalRelocations = 0;
1975 DySymtab->ExternalRelocationsOffset = 0;
1976 DySymtab->UndefinedSymbolsIndex = 0;
1977 DySymtab->NumUndefinedSymbols = 0;
1978 DySymtab->IndirectSymbolsOffset = 0;
1979 DySymtab->NumIndirectSymbols = 0;
1980 } else {
1981 if (NumUndefinedSymbols > 0) {
1982 //
1983 // Copy the entire symbol table excluding undefined symbols.
1984 // Any symbols that point to locations before our kext are ones
1985 // that were previously undefined, and can be skipped.
1986 //
1987 SymtabLinkEdit32 = (MACH_NLIST *)LinkEdit;
1988 NumSymtabLinkEdit32Symbols = 0;
1989 for (Index = 0; Index < NumSymbols; ++Index) {
1990 Symbol = (MACH_NLIST_ANY *)&(&SymbolTable->Symbol32)[Index];
1991 if ( (Symbol->Symbol32.Type == (MACH_N_TYPE_ABS | MACH_N_TYPE_EXT))
1992 && (Symbol->Symbol32.Section == NO_SECT)
1993 && (Symbol->Symbol32.Value < LoadAddress))
1994 {
1995 continue;
1996 }
1997
1998 CopyMem (
1999 &SymtabLinkEdit32[NumSymtabLinkEdit32Symbols++],
2000 Symbol,
2001 sizeof (MACH_NLIST)
2002 );
2003 }
2004
2005 SymtabSize = (UINT32)(NumSymbols * sizeof (MACH_NLIST));
2006 SymtabSize2 = (UINT32)(NumSymtabLinkEdit32Symbols * sizeof (MACH_NLIST));
2007
2008 //
2009 // Zero out the existing symbol table, and copy our non-undefined symbols back.
2010 //
2011 ZeroMem (
2012 (VOID *)((UINTN)FileData + Symtab->SymbolsOffset),
2013 SymtabSize
2014 );
2015 CopyMem (
2016 (VOID *)((UINTN)FileData + Symtab->SymbolsOffset),
2017 SymtabLinkEdit32,
2018 SymtabSize2
2019 );
2020
2021 Symtab->NumSymbols = NumSymtabLinkEdit32Symbols;
2022 }
2023 }
2024
2025 //
2026 // Adapt the link addresses of all Segments and their Sections.
2027 //
2028 SegmentOffset = 0;
2029 SegmentSize = 0;
2030 SegmentVmSizes = 0;
2031
2032 Segment = NULL;
2033 while ((Segment = MachoGetNextSegment (MachoContext, Segment)) != NULL) {
2034 Section = NULL;
2035 while ((Section = MachoGetNextSection (MachoContext, Segment, Section)) != NULL) {
2036 if (Context->Is32Bit) {
2037 Section->Section32.Address = ALIGN_VALUE (
2038 (Section->Section32.Address + (UINT32)LoadAddressOffset),
2039 (UINT32)(1U << Section->Section32.Alignment)
2040 );
2041 } else {
2042 Section->Section64.Address = ALIGN_VALUE (
2043 (Section->Section64.Address + LoadAddressOffset),
2044 (UINT64)(1U << Section->Section64.Alignment)
2045 );
2046 }
2047 }
2048
2049 if (Context->Is32Bit) {
2050 Segment->Segment32.VirtualAddress += (UINT32)LoadAddressOffset;
2051
2052 //
2053 // Logically equivalent to kxld_seg_set_vm_protections.
2054 // Assertion: Not i386 (strict protection).
2055 //
2056 // MH_OBJECT has only one unnamed segment, so all protections need to be enabled.
2057 //
2058 if (AsciiStrnCmp (Segment->Segment32.SegmentName, "", ARRAY_SIZE (Segment->Segment32.SegmentName)) == 0) {
2061 } else if (AsciiStrnCmp (Segment->Segment32.SegmentName, "__TEXT", ARRAY_SIZE (Segment->Segment32.SegmentName)) == 0) {
2064 } else {
2067 }
2068
2069 if (Segment->Segment32.FileOffset > SegmentOffset) {
2070 SegmentOffset = Segment->Segment32.FileOffset;
2071 SegmentSize = Segment->Segment32.FileSize;
2072 }
2073
2074 SegmentVmSizes += Segment->Segment32.Size;
2075 } else {
2076 Segment->Segment64.VirtualAddress += LoadAddressOffset;
2077
2078 //
2079 // Logically equivalent to kxld_seg_set_vm_protections.
2080 // Assertion: Not i386 (strict protection).
2081 //
2082 if (AsciiStrnCmp (Segment->Segment64.SegmentName, "__TEXT", ARRAY_SIZE (Segment->Segment64.SegmentName)) == 0) {
2085 } else {
2088 }
2089
2090 if (Segment->Segment64.FileOffset > SegmentOffset) {
2091 SegmentOffset = (UINT32)Segment->Segment64.FileOffset;
2092 SegmentSize = (UINT32)Segment->Segment64.FileSize;
2093 }
2094
2095 SegmentVmSizes += Segment->Segment64.Size;
2096 }
2097 }
2098
2099 if (Context->Is32Bit) {
2100 //
2101 // Populate kmod information.
2102 //
2103 KmodInfo->Kmod32.Address = (UINT32)LoadAddress;
2104 //
2105 // This is a hack borrowed from XNU. Real header size is equal to:
2106 // sizeof (*MachHeader) + MachHeader->CommandsSize (often aligned to 4096)
2107 // However, it cannot be set to this value unless it exists in a separate segment,
2108 // and presently it is not the case on macOS. When header is put to __TEXT (as usual),
2109 // XNU makes it read only, and this prevents __TEXT from gaining executable permission.
2110 // See OSKext::setVMAttributes.
2111 //
2112 KmodInfo->Kmod32.HdrSize = IsObject32 ? (UINT32)FileOffset : 0;
2113 KmodInfo->Kmod32.Size = IsObject32 ? MachSize : KmodInfo->Kmod32.HdrSize + (UINT32)SegmentVmSizes;
2114 //
2115 // Adapt the Mach-O header to signal being prelinked.
2116 //
2118
2119 if (!IsObject32) {
2120 MachSize = SegmentOffset + SegmentSize;
2121 }
2122 } else {
2123 //
2124 // Populate kmod information.
2125 //
2126 KmodInfo->Kmod64.Address = LoadAddress;
2127 //
2128 // This is a hack borrowed from XNU. Real header size is equal to:
2129 // sizeof (*MachHeader) + MachHeader->CommandsSize (often aligned to 4096)
2130 // However, it cannot be set to this value unless it exists in a separate segment,
2131 // and presently it is not the case on macOS. When header is put to __TEXT (as usual),
2132 // XNU makes it read only, and this prevents __TEXT from gaining executable permission.
2133 // See OSKext::setVMAttributes.
2134 //
2135 KmodInfo->Kmod64.HdrSize = 0;
2136 KmodInfo->Kmod64.Size = KmodInfo->Kmod64.HdrSize + SegmentVmSizes;
2137 //
2138 // Adapt the Mach-O header to signal being prelinked.
2139 //
2141
2142 MachSize = SegmentOffset + SegmentSize;
2143 }
2144
2145 //
2146 // Reinitialize the Mach-O context to account for the changed __LINKEDIT
2147 // segment and file size.
2148 //
2149 if (!MachoInitializeContext (MachoContext, MachoContext->FileData, MachSize, 0, MachSize, Context->Is32Bit)) {
2150 //
2151 // This should never failed under normal and abnormal conditions.
2152 //
2153 ASSERT (FALSE);
2154 return EFI_INVALID_PARAMETER;
2155 }
2156
2157 return EFI_SUCCESS;
2158}
#define ARRAY_SIZE(Array)
Definition AppleMacEfi.h:34
#define MACH_HEADER_FLAG_DYNAMIC_LINKER_LINK
#define NO_SECT
symbol is not in any section
#define MACH_N_TYPE_EXT
#define MACH_RELOC_ABSOLUTE
absolute relocation type for Mach-O files
#define MACH_N_WEAK_DEF
@ MachGenericRelocVanilla
#define MACH_N_TYPE_TYPE
mask for the type bit
#define MACH_HEADER_FLAG_NO_UNDEFINED_REFERENCES
#define MACH_N_TYPE_STAB
#define MACH_N_TYPE_UNDF
undefined, n_sect == NO_SECT
#define MACH_N_TYPE_INDR
indirect
@ MachX8664RelocUnsigned
for absolute addresses
@ MachX8664RelocBranch
@ MachX8664RelocGotLoad
a MOVQ load of a GOT entry
@ MachX8664RelocSigned
for signed 32-bit displacement
@ MachX8664RelocSigned4
@ MachX8664RelocSigned1
@ MachX8664RelocSigned2
@ MachX8664RelocSubtractor
@ MachX8664RelocGot
other GOT references
#define MACH_N_TYPE_SECT
defined in section number n_sect
@ MachHeaderFileTypeObject
#define MACH_N_TYPE_ABS
absolute, n_sect == NO_SECT
#define MACH_INDIRECT_SYMBOL_LOCAL
#define MAX_SECT
1 thru 255 inclusive
#define MACH_INDIRECT_SYMBOL_ABS
UINT64 Length
UINT32 MachoGetInnerSize(IN OUT OC_MACHO_CONTEXT *Context)
Definition Header.c:55
BOOLEAN MachoRelocateSymbol(IN OUT OC_MACHO_CONTEXT *Context, IN UINT64 LinkAddress, IN OUT MACH_NLIST_ANY *Symbol)
Definition Symbols.c:136
UINT32 MachoGetFileSize(IN OUT OC_MACHO_CONTEXT *Context)
Definition Header.c:77
CONST CHAR8 * MachoGetIndirectSymbolName(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_NLIST_ANY *Symbol)
Definition Symbols.c:93
VOID * MachoGetFileData(IN OUT OC_MACHO_CONTEXT *Context)
Definition Header.c:66
VOID * MachoGetFilePointerByAddress(IN OUT OC_MACHO_CONTEXT *Context, IN UINT64 Address, OUT UINT32 *MaxSize OPTIONAL)
Definition Header.c:627
MACH_SEGMENT_COMMAND_ANY * MachoGetNextSegment(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_SEGMENT_COMMAND_ANY *Segment OPTIONAL)
Definition Header.c:160
MACH_HEADER_ANY * MachoGetMachHeader(IN OUT OC_MACHO_CONTEXT *Context)
Definition Header.c:44
BOOLEAN MachoInitializeContext(OUT OC_MACHO_CONTEXT *Context, IN VOID *FileData, IN UINT32 FileSize, IN UINT32 HeaderOffset, IN UINT32 InnerSize, IN BOOLEAN Is32Bit)
Definition Header.c:29
UINT32 MachoGetSymbolTable(IN OUT OC_MACHO_CONTEXT *Context, OUT CONST MACH_NLIST_ANY **SymbolTable, OUT CONST CHAR8 **StringTable OPTIONAL, OUT CONST MACH_NLIST_ANY **LocalSymbols OPTIONAL, OUT UINT32 *NumLocalSymbols OPTIONAL, OUT CONST MACH_NLIST_ANY **ExternalSymbols OPTIONAL, OUT UINT32 *NumExternalSymbols OPTIONAL, OUT CONST MACH_NLIST_ANY **UndefinedSymbols OPTIONAL, OUT UINT32 *NumUndefinedSymbols OPTIONAL)
Definition Header.c:519
BOOLEAN MachoRelocationIsPairIntel64(IN UINT8 Type)
Definition Relocations.c:47
MACH_NLIST_ANY * MachoGetSymbolByIndex(IN OUT OC_MACHO_CONTEXT *Context, IN UINT32 Index)
Definition Symbols.c:67
BOOLEAN MachoPreserveRelocationIntel64(IN UINT8 Type)
Definition Relocations.c:76
BOOLEAN MachoRelocationIsPairIntel32(IN UINT8 Type)
Definition Relocations.c:32
CONST CHAR8 * MachoGetSymbolName(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_NLIST_ANY *Symbol)
Definition Symbols.c:80
MACH_SECTION_ANY * MachoGetNextSection(IN OUT OC_MACHO_CONTEXT *Context, IN MACH_SEGMENT_COMMAND_ANY *Segment, IN MACH_SECTION_ANY *Section OPTIONAL)
Definition Header.c:173
UINT32 MachoGetIndirectSymbolTable(IN OUT OC_MACHO_CONTEXT *Context, OUT CONST MACH_NLIST_ANY **SymbolTable)
Definition Header.c:559
BOOLEAN MachoSymbolNameIsVtable(IN CONST CHAR8 *SymbolName)
Definition CxxSymbols.c:379
#define MACHO_ALIGN(x)
Definition OcMachoLib.h:28
MACH_SECTION * MachoGetSectionByIndex32(IN OUT OC_MACHO_CONTEXT *Context, IN UINT32 Index)
BOOLEAN MachoSymbolNameIsPureVirtual(IN CONST CHAR8 *Name)
Definition CxxSymbols.c:42
MACH_SECTION_ANY * MachoGetSectionByIndex(IN OUT OC_MACHO_CONTEXT *Context, IN UINT32 Index)
Definition Header.c:188
MACH_SECTION_ANY * MachoGetSegmentSectionByName(IN OUT OC_MACHO_CONTEXT *Context, IN CONST CHAR8 *SegmentName, IN CONST CHAR8 *SectionName)
Definition Header.c:228
BOOLEAN MachoSymbolGetFileOffset(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_NLIST_ANY *Symbol, OUT UINT32 *FileOffset, OUT UINT32 *MaxSize OPTIONAL)
Definition Symbols.c:153
CONST PRELINKED_VTABLE * InternalGetOcVtableByName(IN PRELINKED_CONTEXT *Context, IN PRELINKED_KEXT *Kext, IN CONST CHAR8 *Name)
Definition Vtables.c:75
#define X86_64_RIP_RELATIVE_LIMIT
#define VTABLE_ENTRY_SIZE_X(a)
BOOLEAN InternalPatchByVtables(IN PRELINKED_CONTEXT *Context, IN OUT PRELINKED_KEXT *Kext)
Definition Vtables.c:584
OC_GET_SYMBOL_LEVEL
@ OcGetSymbolFirstLevel
@ OcGetSymbolOnlyCxx
#define KXLD_WEAK_TEST_SYMBOL
VOID InternalUnlockContextKexts(IN PRELINKED_CONTEXT *Context)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
UINT64 EFIAPI DivU64x32Remainder(IN UINT64 Dividend, IN UINT32 Divisor, OUT UINT32 *Remainder OPTIONAL)
Definition UserMath.c:25
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition UserMath.c:76
#define ASSERT(x)
Definition coder.h:55
#define DivU64x32(x, y, z)
UINT32 NumExternalSymbols
number of externally defined symbols
UINT32 UndefinedSymbolsIndex
index to undefined symbols
UINT32 NumLocalSymbols
number of local symbols
UINT32 NumOfLocalRelocations
number of local relocation entries
MACH_LOAD_COMMAND_HDR_ UINT32 LocalSymbolsIndex
index to local symbols
UINT32 NumUndefinedSymbols
number of undefined symbols
UINT32 LocalRelocationsOffset
offset to local relocation entries
UINT32 ExternalSymbolsIndex
index to externally defined symbols
MACH_HEADER_FLAGS Flags
flags
MACH_HEADER_FLAGS Flags
flags
MACH_HEADER_FILE_TYPE FileType
type of file
UINT64 Value
value of this symbol (or stab offset)
UINT8 Section
section number or NO_SECT
UINT8 Type
type flag, see below
UINT32 Value
value of this symbol (or stab offset)
UINT32 Extern
does not include value of sym referenced
UINT32 Alignment
section alignment (power of 2)
UINT64 Address
memory address of this section
UINT32 Alignment
section alignment (power of 2)
UINT32 Address
memory address of this section
UINT32 NumRelocations
number of relocation entries
UINT32 RelocationsOffset
file offset of relocation entries
MACH_VM_PROTECTION InitialProtection
initial VM protection
UINT64 FileOffset
file offset of this segment
MACH_LOAD_COMMAND_HDR_ CHAR8 SegmentName[16]
segment Name
UINT64 Size
memory size of this segment
UINT64 FileSize
amount to map from the file
UINT64 VirtualAddress
memory address of this segment
MACH_VM_PROTECTION MaximumProtection
maximum VM protection
UINT32 FileOffset
file offset of this segment
UINT32 Size
memory size of this segment
MACH_VM_PROTECTION InitialProtection
initial VM protection
UINT32 VirtualAddress
memory address of this segment
MACH_VM_PROTECTION MaximumProtection
maximum VM protection
UINT32 FileSize
amount to map from the file
MACH_LOAD_COMMAND_HDR_ CHAR8 SegmentName[16]
segment Name
UINT32 StringsSize
string table size in bytes
MACH_LOAD_COMMAND_HDR_ UINT32 SymbolsOffset
symbol table offset
UINT32 NumSymbols
number of symbol table entries
UINT32 StringsOffset
string table offset
MACH_RELOCATION_INFO * ExternRelocations
Definition OcMachoLib.h:46
MACH_DYSYMTAB_COMMAND * DySymtab
Definition OcMachoLib.h:43
MACH_RELOCATION_INFO * LocalRelocations
Definition OcMachoLib.h:45
MACH_SYMTAB_COMMAND * Symtab
Definition OcMachoLib.h:40
PRELINKED_KEXT * Dependencies[MAX_KEXT_DEPEDENCIES]
KMOD_INFO_32_V1 Kmod32
KMOD_INFO_64_V1 Kmod64
MACH_HEADER_64 Header64
MACH_NLIST_64 Symbol64
MACH_SECTION Section32
MACH_SECTION_64 Section64
MACH_SEGMENT_COMMAND_64 Segment64
MACH_SEGMENT_COMMAND Segment32