无法在 LLVM OrcJIT 中跨模块访问符号
Cannot access symbols across modules in LLVM OrcJIT
我正在使用 haskell、LLVM-hs 和 OrcJIT 编写 JIT 编译器。这是我编译模块的主文件,将它们添加到 JIT 并获取和 运行s 内部主要功能:
main :: IO ()
main =
withContext $ \ctx ->
withExecutionSession $ \es ->
withHostTargetMachine Reloc.PIC CodeModel.Default CodeGenOpt.None $ \tm ->
withSymbolResolver es myResolver $ \psr ->
withObjectLinkingLayer es (\_ -> return psr) $ \oll ->
withIRCompileLayer oll tm $ \ircl -> do
loadLibraryPermanently Nothing
repl ctx es tm ircl
where
myResolver :: SymbolResolver
myResolver = SymbolResolver $ \mangled -> do
ptr <- getSymbolAddressInProcess mangled
return $ Right $ JITSymbol
{ jitSymbolAddress = ptr
, jitSymbolFlags = defaultJITSymbolFlags { jitSymbolExported = True }
}
repl :: Context -> ExecutionSession -> TargetMachine -> IRCompileLayer ObjectLinkingLayer -> IO ()
repl ctx es tm cl = runInputT defaultSettings (loop C.initCmpState)
where
loop :: C.CmpState -> InputT IO ()
loop state =
getInputLine "% " >>= \minput -> case minput of
Nothing -> return ()
Just "q" -> return ()
Just input -> liftIO (process state input) >>= loop
process :: C.CmpState -> String -> IO C.CmpState
process state source =
case L.alexScanner source of
Left errStr -> putStrLn errStr >> return state
Right tokens -> case (P.parseTokens tokens) 0 of
P.ParseOk ast ->
let (res, state') = C.codeGen state (head ast) in
case res of
Left err -> putStrLn (show err) >> return state
Right () -> runDefinition (state' { C.externs = C.externs state }) >> return state'
{ C.globals = Map.empty
, C.instructions = []
}
runDefinition :: C.CmpState -> IO ()
runDefinition state = do
let globals = Map.elems (C.globals state)
let externs = Map.elems (C.externs state)
let instructions = reverse (C.instructions state)
let mainName = mkBSS "main.0"
let mainFn = GlobalDefinition $ functionDefaults
{ returnType = void
, name = Name mainName
, basicBlocks = [BasicBlock (mkName "entry") instructions (Do $ Ret Nothing [])]
}
case instructions of
[] -> do
let astmod = defaultModule
{ moduleDefinitions = externs ++ globals
}
M.withModuleFromAST ctx astmod $ \mod -> do
BS.putStrLn =<< M.moduleLLVMAssembly mod
withModuleKey es $ \modKey ->
addModule cl modKey mod
x -> do
let astmod = defaultModule
{ moduleDefinitions = externs ++ globals ++ [mainFn]
}
M.withModuleFromAST ctx astmod $ \mod -> do
BS.putStrLn =<< M.moduleLLVMAssembly mod
withModuleKey es $ \modKey ->
withModule cl modKey mod $ do
res <- (\mangled -> findSymbol cl mangled False) =<< mangleSymbol cl mainName
case res of
Left _ -> putStrLn ("Couldn't find: " ++ show mainName)
Right (JITSymbol fn _)-> do
run $ castPtrToFunPtr (wordPtrToPtr fn)
正确隔离模块,例如此打印语句运行。具有 main 功能的模块在执行后从 JIT 中删除:
print(234);
; ModuleID = '<string>'
source_filename = "<string>"
@0 = constant [4 x i8] c"%d[=11=]A[=11=]"
declare i32 @printf(i8*, ...)
define void @main.0() {
entry:
%0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i32 0, i32 0), i32 234)
ret void
}
234
将 4 分配给符号 'x' 会产生一个带有全局变量的模块,该模块不会从 JIT 中删除:
x := 4;
; ModuleID = '<string>'
source_filename = "<string>"
@x = global i32 4
但是尝试在下一条语句中打印 'x' 会导致主函数查找失败:
print(x);
; ModuleID = '<string>'
source_filename = "<string>"
@x = external global i32
@0 = constant [4 x i8] c"%d[=13=]A[=13=]"
declare i32 @printf(i8*, ...)
define void @main.0() {
entry:
%0 = load i32, i32* @x
%1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i32 0, i32 0), i32 %0)
ret void
}
Couldn't find: "main.0"
跨模块访问符号时出现问题。
我尝试过的事情:
- 访问函数而不是变量
- 更改我的符号解析器以使用 'findSymbol' 而不是 llvm-hs-examples 存储库中的 'getSymbolAddressInProcess'。这阻止了任何模块 运行ning.
- 正在下载 llvm-hs-examples 存储库和 运行正在下载 'orc' 示例。 这也导致了符号错误!
- 在新的 linux 安装中重新下载 haskell 工具链和 llvm/llvm-hs (9.0.1)。
如有任何帮助,我将不胜感激!
已解决!我对符号解析器感到困惑。它不用于在使用 'findSymbol' 时检索符号,而是在 JIT 的编译和链接阶段。 'getSymbolAddressInProcess' 将仅搜索主机进程中的符号(例如 printf),而不是 JIT 中定义的符号(例如 x)。
为了在 JIT 中使用从另一个模块检索外部符号 'x' 并从主机进程检索 'printf' 的模块,必须添加一个符号解析器来搜索 JIT 编译图层和符号的主机进程:
myResolver :: IRCompileLayer ObjectLinkingLayer -> SymbolResolver
myResolver ircl = SymbolResolver $ \mangled -> do
symbol <- findSymbol ircl mangled False
case symbol of
Right _ -> return symbol
Left _ -> do
ptr <- getSymbolAddressInProcess mangled
return $ Right $ JITSymbol
{ jitSymbolAddress = ptr
, jitSymbolFlags = defaultJITSymbolFlags { jitSymbolExported = True }
}
我正在使用 haskell、LLVM-hs 和 OrcJIT 编写 JIT 编译器。这是我编译模块的主文件,将它们添加到 JIT 并获取和 运行s 内部主要功能:
main :: IO ()
main =
withContext $ \ctx ->
withExecutionSession $ \es ->
withHostTargetMachine Reloc.PIC CodeModel.Default CodeGenOpt.None $ \tm ->
withSymbolResolver es myResolver $ \psr ->
withObjectLinkingLayer es (\_ -> return psr) $ \oll ->
withIRCompileLayer oll tm $ \ircl -> do
loadLibraryPermanently Nothing
repl ctx es tm ircl
where
myResolver :: SymbolResolver
myResolver = SymbolResolver $ \mangled -> do
ptr <- getSymbolAddressInProcess mangled
return $ Right $ JITSymbol
{ jitSymbolAddress = ptr
, jitSymbolFlags = defaultJITSymbolFlags { jitSymbolExported = True }
}
repl :: Context -> ExecutionSession -> TargetMachine -> IRCompileLayer ObjectLinkingLayer -> IO ()
repl ctx es tm cl = runInputT defaultSettings (loop C.initCmpState)
where
loop :: C.CmpState -> InputT IO ()
loop state =
getInputLine "% " >>= \minput -> case minput of
Nothing -> return ()
Just "q" -> return ()
Just input -> liftIO (process state input) >>= loop
process :: C.CmpState -> String -> IO C.CmpState
process state source =
case L.alexScanner source of
Left errStr -> putStrLn errStr >> return state
Right tokens -> case (P.parseTokens tokens) 0 of
P.ParseOk ast ->
let (res, state') = C.codeGen state (head ast) in
case res of
Left err -> putStrLn (show err) >> return state
Right () -> runDefinition (state' { C.externs = C.externs state }) >> return state'
{ C.globals = Map.empty
, C.instructions = []
}
runDefinition :: C.CmpState -> IO ()
runDefinition state = do
let globals = Map.elems (C.globals state)
let externs = Map.elems (C.externs state)
let instructions = reverse (C.instructions state)
let mainName = mkBSS "main.0"
let mainFn = GlobalDefinition $ functionDefaults
{ returnType = void
, name = Name mainName
, basicBlocks = [BasicBlock (mkName "entry") instructions (Do $ Ret Nothing [])]
}
case instructions of
[] -> do
let astmod = defaultModule
{ moduleDefinitions = externs ++ globals
}
M.withModuleFromAST ctx astmod $ \mod -> do
BS.putStrLn =<< M.moduleLLVMAssembly mod
withModuleKey es $ \modKey ->
addModule cl modKey mod
x -> do
let astmod = defaultModule
{ moduleDefinitions = externs ++ globals ++ [mainFn]
}
M.withModuleFromAST ctx astmod $ \mod -> do
BS.putStrLn =<< M.moduleLLVMAssembly mod
withModuleKey es $ \modKey ->
withModule cl modKey mod $ do
res <- (\mangled -> findSymbol cl mangled False) =<< mangleSymbol cl mainName
case res of
Left _ -> putStrLn ("Couldn't find: " ++ show mainName)
Right (JITSymbol fn _)-> do
run $ castPtrToFunPtr (wordPtrToPtr fn)
正确隔离模块,例如此打印语句运行。具有 main 功能的模块在执行后从 JIT 中删除:
print(234);
; ModuleID = '<string>'
source_filename = "<string>"
@0 = constant [4 x i8] c"%d[=11=]A[=11=]"
declare i32 @printf(i8*, ...)
define void @main.0() {
entry:
%0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i32 0, i32 0), i32 234)
ret void
}
234
将 4 分配给符号 'x' 会产生一个带有全局变量的模块,该模块不会从 JIT 中删除:
x := 4;
; ModuleID = '<string>'
source_filename = "<string>"
@x = global i32 4
但是尝试在下一条语句中打印 'x' 会导致主函数查找失败:
print(x);
; ModuleID = '<string>'
source_filename = "<string>"
@x = external global i32
@0 = constant [4 x i8] c"%d[=13=]A[=13=]"
declare i32 @printf(i8*, ...)
define void @main.0() {
entry:
%0 = load i32, i32* @x
%1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i32 0, i32 0), i32 %0)
ret void
}
Couldn't find: "main.0"
跨模块访问符号时出现问题。
我尝试过的事情:
- 访问函数而不是变量
- 更改我的符号解析器以使用 'findSymbol' 而不是 llvm-hs-examples 存储库中的 'getSymbolAddressInProcess'。这阻止了任何模块 运行ning.
- 正在下载 llvm-hs-examples 存储库和 运行正在下载 'orc' 示例。 这也导致了符号错误!
- 在新的 linux 安装中重新下载 haskell 工具链和 llvm/llvm-hs (9.0.1)。
如有任何帮助,我将不胜感激!
已解决!我对符号解析器感到困惑。它不用于在使用 'findSymbol' 时检索符号,而是在 JIT 的编译和链接阶段。 'getSymbolAddressInProcess' 将仅搜索主机进程中的符号(例如 printf),而不是 JIT 中定义的符号(例如 x)。
为了在 JIT 中使用从另一个模块检索外部符号 'x' 并从主机进程检索 'printf' 的模块,必须添加一个符号解析器来搜索 JIT 编译图层和符号的主机进程:
myResolver :: IRCompileLayer ObjectLinkingLayer -> SymbolResolver
myResolver ircl = SymbolResolver $ \mangled -> do
symbol <- findSymbol ircl mangled False
case symbol of
Right _ -> return symbol
Left _ -> do
ptr <- getSymbolAddressInProcess mangled
return $ Right $ JITSymbol
{ jitSymbolAddress = ptr
, jitSymbolFlags = defaultJITSymbolFlags { jitSymbolExported = True }
}