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