From 5917b8baa2b817a5962ce52d64ca59dd7e0824c6 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 b58d7f966..38001a069 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 5a2343c43..589c0c6f7 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.