109467b48Spatrick //===- SafeStackLayout.cpp - SafeStack frame layout -----------------------===// 209467b48Spatrick // 309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information. 509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 609467b48Spatrick // 709467b48Spatrick //===----------------------------------------------------------------------===// 809467b48Spatrick 909467b48Spatrick #include "SafeStackLayout.h" 10*097a140dSpatrick #include "llvm/Analysis/StackLifetime.h" 1109467b48Spatrick #include "llvm/IR/Value.h" 1209467b48Spatrick #include "llvm/Support/CommandLine.h" 1309467b48Spatrick #include "llvm/Support/Compiler.h" 1409467b48Spatrick #include "llvm/Support/Debug.h" 1509467b48Spatrick #include "llvm/Support/MathExtras.h" 1609467b48Spatrick #include "llvm/Support/raw_ostream.h" 1709467b48Spatrick #include <algorithm> 1809467b48Spatrick #include <cassert> 1909467b48Spatrick 2009467b48Spatrick using namespace llvm; 2109467b48Spatrick using namespace llvm::safestack; 2209467b48Spatrick 2309467b48Spatrick #define DEBUG_TYPE "safestacklayout" 2409467b48Spatrick 2509467b48Spatrick static cl::opt<bool> ClLayout("safe-stack-layout", 2609467b48Spatrick cl::desc("enable safe stack layout"), cl::Hidden, 2709467b48Spatrick cl::init(true)); 2809467b48Spatrick 2909467b48Spatrick LLVM_DUMP_METHOD void StackLayout::print(raw_ostream &OS) { 3009467b48Spatrick OS << "Stack regions:\n"; 3109467b48Spatrick for (unsigned i = 0; i < Regions.size(); ++i) { 3209467b48Spatrick OS << " " << i << ": [" << Regions[i].Start << ", " << Regions[i].End 3309467b48Spatrick << "), range " << Regions[i].Range << "\n"; 3409467b48Spatrick } 3509467b48Spatrick OS << "Stack objects:\n"; 3609467b48Spatrick for (auto &IT : ObjectOffsets) { 3709467b48Spatrick OS << " at " << IT.getSecond() << ": " << *IT.getFirst() << "\n"; 3809467b48Spatrick } 3909467b48Spatrick } 4009467b48Spatrick 4109467b48Spatrick void StackLayout::addObject(const Value *V, unsigned Size, unsigned Alignment, 42*097a140dSpatrick const StackLifetime::LiveRange &Range) { 4309467b48Spatrick StackObjects.push_back({V, Size, Alignment, Range}); 4409467b48Spatrick ObjectAlignments[V] = Alignment; 4509467b48Spatrick MaxAlignment = std::max(MaxAlignment, Alignment); 4609467b48Spatrick } 4709467b48Spatrick 4809467b48Spatrick static unsigned AdjustStackOffset(unsigned Offset, unsigned Size, 4909467b48Spatrick unsigned Alignment) { 5009467b48Spatrick return alignTo(Offset + Size, Alignment) - Size; 5109467b48Spatrick } 5209467b48Spatrick 5309467b48Spatrick void StackLayout::layoutObject(StackObject &Obj) { 5409467b48Spatrick if (!ClLayout) { 5509467b48Spatrick // If layout is disabled, just grab the next aligned address. 5609467b48Spatrick // This effectively disables stack coloring as well. 5709467b48Spatrick unsigned LastRegionEnd = Regions.empty() ? 0 : Regions.back().End; 5809467b48Spatrick unsigned Start = AdjustStackOffset(LastRegionEnd, Obj.Size, Obj.Alignment); 5909467b48Spatrick unsigned End = Start + Obj.Size; 6009467b48Spatrick Regions.emplace_back(Start, End, Obj.Range); 6109467b48Spatrick ObjectOffsets[Obj.Handle] = End; 6209467b48Spatrick return; 6309467b48Spatrick } 6409467b48Spatrick 6509467b48Spatrick LLVM_DEBUG(dbgs() << "Layout: size " << Obj.Size << ", align " 6609467b48Spatrick << Obj.Alignment << ", range " << Obj.Range << "\n"); 6709467b48Spatrick assert(Obj.Alignment <= MaxAlignment); 6809467b48Spatrick unsigned Start = AdjustStackOffset(0, Obj.Size, Obj.Alignment); 6909467b48Spatrick unsigned End = Start + Obj.Size; 7009467b48Spatrick LLVM_DEBUG(dbgs() << " First candidate: " << Start << " .. " << End << "\n"); 7109467b48Spatrick for (const StackRegion &R : Regions) { 7209467b48Spatrick LLVM_DEBUG(dbgs() << " Examining region: " << R.Start << " .. " << R.End 7309467b48Spatrick << ", range " << R.Range << "\n"); 7409467b48Spatrick assert(End >= R.Start); 7509467b48Spatrick if (Start >= R.End) { 7609467b48Spatrick LLVM_DEBUG(dbgs() << " Does not intersect, skip.\n"); 7709467b48Spatrick continue; 7809467b48Spatrick } 79*097a140dSpatrick if (Obj.Range.overlaps(R.Range)) { 8009467b48Spatrick // Find the next appropriate location. 8109467b48Spatrick Start = AdjustStackOffset(R.End, Obj.Size, Obj.Alignment); 8209467b48Spatrick End = Start + Obj.Size; 8309467b48Spatrick LLVM_DEBUG(dbgs() << " Overlaps. Next candidate: " << Start << " .. " 8409467b48Spatrick << End << "\n"); 8509467b48Spatrick continue; 8609467b48Spatrick } 8709467b48Spatrick if (End <= R.End) { 8809467b48Spatrick LLVM_DEBUG(dbgs() << " Reusing region(s).\n"); 8909467b48Spatrick break; 9009467b48Spatrick } 9109467b48Spatrick } 9209467b48Spatrick 9309467b48Spatrick unsigned LastRegionEnd = Regions.empty() ? 0 : Regions.back().End; 9409467b48Spatrick if (End > LastRegionEnd) { 9509467b48Spatrick // Insert a new region at the end. Maybe two. 9609467b48Spatrick if (Start > LastRegionEnd) { 9709467b48Spatrick LLVM_DEBUG(dbgs() << " Creating gap region: " << LastRegionEnd << " .. " 9809467b48Spatrick << Start << "\n"); 99*097a140dSpatrick Regions.emplace_back(LastRegionEnd, Start, StackLifetime::LiveRange(0)); 10009467b48Spatrick LastRegionEnd = Start; 10109467b48Spatrick } 10209467b48Spatrick LLVM_DEBUG(dbgs() << " Creating new region: " << LastRegionEnd << " .. " 10309467b48Spatrick << End << ", range " << Obj.Range << "\n"); 10409467b48Spatrick Regions.emplace_back(LastRegionEnd, End, Obj.Range); 10509467b48Spatrick LastRegionEnd = End; 10609467b48Spatrick } 10709467b48Spatrick 10809467b48Spatrick // Split starting and ending regions if necessary. 10909467b48Spatrick for (unsigned i = 0; i < Regions.size(); ++i) { 11009467b48Spatrick StackRegion &R = Regions[i]; 11109467b48Spatrick if (Start > R.Start && Start < R.End) { 11209467b48Spatrick StackRegion R0 = R; 11309467b48Spatrick R.Start = R0.End = Start; 11409467b48Spatrick Regions.insert(&R, R0); 11509467b48Spatrick continue; 11609467b48Spatrick } 11709467b48Spatrick if (End > R.Start && End < R.End) { 11809467b48Spatrick StackRegion R0 = R; 11909467b48Spatrick R0.End = R.Start = End; 12009467b48Spatrick Regions.insert(&R, R0); 12109467b48Spatrick break; 12209467b48Spatrick } 12309467b48Spatrick } 12409467b48Spatrick 12509467b48Spatrick // Update live ranges for all affected regions. 12609467b48Spatrick for (StackRegion &R : Regions) { 12709467b48Spatrick if (Start < R.End && End > R.Start) 128*097a140dSpatrick R.Range.join(Obj.Range); 12909467b48Spatrick if (End <= R.End) 13009467b48Spatrick break; 13109467b48Spatrick } 13209467b48Spatrick 13309467b48Spatrick ObjectOffsets[Obj.Handle] = End; 13409467b48Spatrick } 13509467b48Spatrick 13609467b48Spatrick void StackLayout::computeLayout() { 13709467b48Spatrick // Simple greedy algorithm. 13809467b48Spatrick // If this is replaced with something smarter, it must preserve the property 13909467b48Spatrick // that the first object is always at the offset 0 in the stack frame (for 14009467b48Spatrick // StackProtectorSlot), or handle stack protector in some other way. 14109467b48Spatrick 14209467b48Spatrick // Sort objects by size (largest first) to reduce fragmentation. 14309467b48Spatrick if (StackObjects.size() > 2) 14409467b48Spatrick std::stable_sort(StackObjects.begin() + 1, StackObjects.end(), 14509467b48Spatrick [](const StackObject &a, const StackObject &b) { 14609467b48Spatrick return a.Size > b.Size; 14709467b48Spatrick }); 14809467b48Spatrick 14909467b48Spatrick for (auto &Obj : StackObjects) 15009467b48Spatrick layoutObject(Obj); 15109467b48Spatrick 15209467b48Spatrick LLVM_DEBUG(print(dbgs())); 15309467b48Spatrick } 154