[PATCH] D37585: Add ARM backend support for pagerando

Stephen Crane via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 7 16:35:56 PST 2017


rinon added a comment.

In https://reviews.llvm.org/D37585#911791, @peter.smith wrote:

> I'm mostly a linker person so I'm not best qualified to review the backend changes. I've tried to take a look from an overall toolchain perspective.


Thanks again!

> How does pagerando handle the Arm exception tables? ...

Yes, pagerando disrupts the PREL relocations in the exidx tables. Our current solution is to extend the platform or C++ runtime libunwind (_Unwind_RaiseException) to canonicalize the IP back to its original offset in the file + the DSO base address before looking it up in the exidx tables. Depending on the platform and libunwind implementation, this information may be easily available in `/proc/PID/maps`. I believe the upstream libunwind actually does load maps if available. However, we probably can't rely on reading the maps file, since the LLVM libunwind does not use it.

The alternative to canonicalizing the IP would be, as you pointed out, to dynamically relocate the exception handling table, but that will add more load time and break the ARM spec, both of which seem unacceptable to me. Additionally, unwind libraries that read the ELF file from disk (without those relocations) will still be confused.

The following is a brief description of how we can use the POT to canonicalize addresses for unwinding without reading `/proc/PID/maps`. I should probably add this to the overall RFC, sorry for not covering this earlier.

In order to not rely on `/proc/PID/maps`, we must first find the POT entry for the current IP. To find the correct POT entry the unwinder must first find the POT for the current stack frame, which will always be located at the address in R9, assuming that unwinding of deeper stack frames was correct and the unwinder was able to retrieve R9 from its callee-saved stack slot. The unwinder can then iterate the POT and find the entry with the largest value <= IP, which should be the POT entry for the bin containing IP.

We can extract the required segment file offset information from the ELF program headers. As long as the linker preserves the ordering of the pagerando segments between the ELF file and their position in the POT, the unwinder can look up the segment corresponding to the POT index found in the previous step. This segment's program header gives us both the original file offset, as well as the segment size, allowing the unwinder to double check that IP indeed falls into that segment.

With a pagerando-randomized IP and the file offset of the corresponding ELF segment, the unwinder can canonicalize the IP to the address it would be located at if all pagerando pages had been laid out contiguously with the rest of the DSO. Using this canonical IP allows the exception handling table to be referenced normally, without any dynamic relocations.



================
Comment at: lib/Target/ARM/ARMAsmPrinter.cpp:891
+    //
+    // Note: This requires LTO.
+    auto *F = cast<Function>(cast<ARMConstantPoolConstant>(ACPV)->getGV());
----------------
peter.smith wrote:
> What happens if LTO is not used? Is it just that only the current module gets put into bins and the rest isn't which is sub-optimal but correct or is it fatal? If it is fatal is there any way of asserting that LTO is required, if not then can the comment be expanded?
Calculating the static offset for a POT entry during code generation requires that the entire POT is laid out in the compiler, which requires LTO. We would need a new static relocation to refer to a POT entry if the POT was constructed after code generation. I'll add that to the comment here.

I don't know any good way to check for LTO at this point. POTOFF modifiers should only be emitted for functions marked with the pagerando attribute, and that is only done by a pass run during LTO. I'll look around to see if there might be a way to assert on this.


================
Comment at: lib/Target/ARM/ARMFastISel.cpp:2969
+  ARMConstantPoolValue *CPV;
+  if (Subtarget->isPIP()) {
+    CPV = ARMConstantPoolConstant::Create(GV, ARMCP::GOTOFF);
----------------
peter.smith wrote:
> style nit, I think that there is only one statement so the braces aren't needed.
Sorry about that. I've seen both styles for if followed by multi-line so I wasn't sure. Fixed now.


================
Comment at: lib/Target/ARM/ARMISelLowering.cpp:2050
+      ARMConstantPoolValue *CPV;
+      if (Subtarget->isPIP())
+        CPV = ARMConstantPoolConstant::Create(GV, ARMCP::GOTOFF);
----------------
peter.smith wrote:
> Given the assert above, could this be true?
Given that we don't support pagerando for Windows, no, this can never be hit. Besides, we already handle PIP addressing in the `UsePIPAddressing` branch. I'll remove this.


https://reviews.llvm.org/D37585





More information about the llvm-commits mailing list