From 95e4dcfb53ed760d158d104c6e3fb082557e24ed Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Wed, 19 May 2021 13:02:48 +0200 Subject: [PATCH] interp: ignore inline assembly in markExternal The markExternal function is used when a global (function or global variable) is somehow run at runtime. All the other globals it refers to are from then on no longer known at compile time, so can't be used by the interp package anymore. This can also include inline assembly. While it is possible to modify globals that way, it is only possible to modify exported globals: similar to calling an undefined function (in C for example). --- interp/memory.go | 3 +++ interp/testdata/basic.ll | 12 ++++++++++++ interp/testdata/basic.out.ll | 7 +++++++ 3 files changed, 22 insertions(+) diff --git a/interp/memory.go b/interp/memory.go index 54bfcb62..ccd98c8b 100644 --- a/interp/memory.go +++ b/interp/memory.go @@ -178,6 +178,9 @@ func (mv *memoryView) markExternal(llvmValue llvm.Value, mark uint8) { default: panic("interp: unknown constant expression") } + } else if !llvmValue.IsAInlineAsm().IsNil() { + // Inline assembly can modify globals but only exported globals. Let's + // hope the author knows what they're doing. } else { llvmType := llvmValue.Type() switch llvmType.TypeKind() { diff --git a/interp/testdata/basic.ll b/interp/testdata/basic.ll index 00117058..d0af3af3 100644 --- a/interp/testdata/basic.ll +++ b/interp/testdata/basic.ll @@ -66,6 +66,9 @@ entry: call void @modifyExternal(i32* bitcast (void ()* @willModifyGlobal to i32*)) store i16 7, i16* @main.exposedValue2 + ; Test that inline assembly is ignored. + call void @modifyExternal(i32* bitcast (void ()* @hasInlineAsm to i32*)) + ; Test switch statement. %switch1 = call i64 @testSwitch(i64 1) ; 1 returns 6 %switch2 = call i64 @testSwitch(i64 9) ; 9 returns the default value -1 @@ -102,6 +105,15 @@ entry: ret void } +; Inline assembly should be ignored in the interp package. While it is possible +; to modify other globals that way, usually that's not the case and there is no +; real way to check. +define void @hasInlineAsm() { +entry: + call void asm sideeffect "", ""() + ret void +} + define i64 @testSwitch(i64 %val) { entry: ; Test switch statement. diff --git a/interp/testdata/basic.out.ll b/interp/testdata/basic.out.ll index 24f5558b..51a3b3f4 100644 --- a/interp/testdata/basic.out.ll +++ b/interp/testdata/basic.out.ll @@ -26,6 +26,7 @@ entry: store i16 5, i16* @main.exposedValue1 call void @modifyExternal(i32* bitcast (void ()* @willModifyGlobal to i32*)) store i16 7, i16* @main.exposedValue2 + call void @modifyExternal(i32* bitcast (void ()* @hasInlineAsm to i32*)) call void @runtime.printint64(i64 6) call void @runtime.printint64(i64 -1) %agg = call { i8, i32, { float, { i64, i16 } } } @nestedStruct() @@ -59,6 +60,12 @@ entry: ret void } +define void @hasInlineAsm() { +entry: + call void asm sideeffect "", ""() + ret void +} + define i64 @testSwitch(i64 %val) local_unnamed_addr { entry: switch i64 %val, label %otherwise [