From 824e13d6d70bd61a68d2e30d9ecd4bd9cc7022c3 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sun, 27 Dec 2020 00:18:05 +0100 Subject: [PATCH] interp: fix alignment of untyped globals During a run of interp, some memory (for example, memory allocated through runtime.alloc) may not have a known LLVM type. This memory is alllocated by creating an i8 array. This does not necessarily work, as i8 has no alignment requirements while the allocated object may have allocation requirements. Therefore, the resulting global may have an alignment that is too loose. This works on some microcontrollers but notably does not work on a Cortex-M0 or Cortex-M0+, as all load/store operations must be aligned. This commit fixes this by setting the alignment of untyped memory to the maximum alignment. The determination of "maximum alignment" is not great but should get the job done on most architectures. --- interp/interp.go | 4 ++++ interp/memory.go | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/interp/interp.go b/interp/interp.go index b58d7f966f..38001a069a 100644 --- a/interp/interp.go +++ b/interp/interp.go @@ -21,6 +21,8 @@ type runner struct { targetData llvm.TargetData builder llvm.Builder pointerSize uint32 // cached pointer size from the TargetData + i8ptrType llvm.Type // often used type so created in advance + maxAlign int // maximum alignment of an object, alignment of runtime.alloc() result debug bool // log debug messages pkgName string // package name of the currently executing package functionCache map[llvm.Value]*function // cache of compiled functions @@ -43,6 +45,8 @@ func Run(mod llvm.Module, debug bool) error { start: time.Now(), } r.pointerSize = uint32(r.targetData.PointerSize()) + r.i8ptrType = llvm.PointerType(mod.Context().Int8Type(), 0) + r.maxAlign = r.targetData.PrefTypeAlignment(r.i8ptrType) // assume pointers are maximally aligned (this is not always the case) initAll := mod.NamedFunction("runtime.initAll") bb := initAll.EntryBasicBlock() diff --git a/interp/memory.go b/interp/memory.go index 5a2343c43c..589c0c6f7b 100644 --- a/interp/memory.go +++ b/interp/memory.go @@ -522,6 +522,7 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) llvm.Valu globalType := initializer.Type() llvmValue = llvm.AddGlobal(mem.r.mod, globalType, obj.globalName) llvmValue.SetInitializer(initializer) + llvmValue.SetAlignment(mem.r.maxAlign) obj.llvmGlobal = llvmValue mem.put(v.index(), obj) } else { @@ -795,7 +796,6 @@ func (v *mapValue) toLLVMValue(hashmapType llvm.Type, mem *memoryView) llvm.Valu // Convert these buckets into LLVM global variables. ctx := v.r.mod.Context() - i8ptrType := llvm.PointerType(ctx.Int8Type(), 0) var nextBucket llvm.Value for i := len(buckets) - 1; i >= 0; i-- { bucket = buckets[i] @@ -804,9 +804,9 @@ func (v *mapValue) toLLVMValue(hashmapType llvm.Type, mem *memoryView) llvm.Valu } firstBucket := nextBucket if firstBucket.IsNil() { - firstBucket = llvm.ConstNull(i8ptrType) + firstBucket = llvm.ConstNull(mem.r.i8ptrType) } else { - firstBucket = llvm.ConstBitCast(firstBucket, i8ptrType) + firstBucket = llvm.ConstBitCast(firstBucket, mem.r.i8ptrType) } // Create the hashmap itself, pointing to these buckets.