- case R_AARCH64_ADR_PREL_LO21:\r
- if (Rel->r_addend != 0 ) { /* TODO */\r
- Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_ADR_PREL_LO21 Need to fixup with addend!.");\r
- }\r
- break;\r
+ case R_AARCH64_ADR_PREL_PG_HI21:\r
+ //\r
+ // AArch64 PG_H21 relocations are typically paired with ABS_LO12\r
+ // relocations, where a PC-relative reference with +/- 4 GB range is\r
+ // split into a relative high part and an absolute low part. Since\r
+ // the absolute low part represents the offset into a 4 KB page, we\r
+ // either have to convert the ADRP into an ADR instruction, or we\r
+ // need to use a section alignment of at least 4 KB, so that the\r
+ // binary appears at a correct offset at runtime. In any case, we\r
+ // have to make sure that the 4 KB relative offsets of both the\r
+ // section containing the reference as well as the section to which\r
+ // it refers have not been changed during PE/COFF conversion (i.e.,\r
+ // in ScanSections64() above).\r
+ //\r
+ if (mCoffAlignment < 0x1000) {\r
+ //\r
+ // Attempt to convert the ADRP into an ADR instruction.\r
+ // This is only possible if the symbol is within +/- 1 MB.\r
+ //\r
+ INT64 Offset;\r
+\r
+ // Decode the ADRP instruction\r
+ Offset = (INT32)((*(UINT32 *)Targ & 0xffffe0) << 8);\r
+ Offset = (Offset << (6 - 5)) | ((*(UINT32 *)Targ & 0x60000000) >> (29 - 12));\r
+\r
+ //\r
+ // ADRP offset is relative to the previous page boundary,\r
+ // whereas ADR offset is relative to the instruction itself.\r
+ // So fix up the offset so it points to the page containing\r
+ // the symbol.\r
+ //\r
+ Offset -= (UINTN)(Targ - mCoffFile) & 0xfff;\r
+\r
+ if (Offset < -0x100000 || Offset > 0xfffff) {\r
+ Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s due to its size (> 1 MB), this module requires 4 KB section alignment.",\r
+ mInImageName);\r
+ break;\r
+ }\r