mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-09 12:32:33 +03:00
Add LLVM-pass plugin support to LDC. Commandline flag: -plugin=...
. (#2554)
This adds functionality to load plugins such as the AFL llvm-mode plugin: https://github.com/mirrorer/afl/blob/master/llvm_mode/afl-llvm-pass.so.cc Note that such plugins developed for Clang should also work for LDC !
This commit is contained in:
parent
b22d8cccf3
commit
16ecb3e79f
9 changed files with 196 additions and 0 deletions
|
@ -321,6 +321,7 @@ set(DRV_SRC
|
||||||
driver/linker-gcc.cpp
|
driver/linker-gcc.cpp
|
||||||
driver/linker-msvc.cpp
|
driver/linker-msvc.cpp
|
||||||
driver/main.cpp
|
driver/main.cpp
|
||||||
|
driver/plugins.cpp
|
||||||
${CMAKE_BINARY_DIR}/driver/ldc-version.cpp
|
${CMAKE_BINARY_DIR}/driver/ldc-version.cpp
|
||||||
)
|
)
|
||||||
set(DRV_HDR
|
set(DRV_HDR
|
||||||
|
@ -337,6 +338,7 @@ set(DRV_HDR
|
||||||
driver/ldc-version.h
|
driver/ldc-version.h
|
||||||
driver/archiver.h
|
driver/archiver.h
|
||||||
driver/linker.h
|
driver/linker.h
|
||||||
|
driver/plugins.h
|
||||||
driver/targetmachine.h
|
driver/targetmachine.h
|
||||||
driver/toobj.h
|
driver/toobj.h
|
||||||
driver/tool.h
|
driver/tool.h
|
||||||
|
@ -559,6 +561,24 @@ if(LDC_WITH_LLD)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Plugin support
|
||||||
|
if(UNIX)
|
||||||
|
set(LDC_ENABLE_PLUGINS_DEFAULT ON)
|
||||||
|
else()
|
||||||
|
set(LDC_ENABLE_PLUGINS_DEFAULT OFF)
|
||||||
|
endif()
|
||||||
|
set(LDC_ENABLE_PLUGINS ${LDC_ENABLE_PLUGINS_DEFAULT} CACHE BOOL "Build LDC with plugin support (increases binary size)")
|
||||||
|
if(LDC_ENABLE_PLUGINS)
|
||||||
|
message(STATUS "Building LDC with plugin support (LDC_ENABLE_PLUGINS=ON)")
|
||||||
|
add_definitions(-DLDC_ENABLE_PLUGINS)
|
||||||
|
# For plugin support, we need to link with --export-dynamic on Unix.
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
set(LDC_LINKERFLAG_LIST "${LDC_LINKERFLAG_LIST};-Wl,--export-dynamic")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(STATUS "Building LDC without plugin support (LDC_ENABLE_PLUGINS=OFF)")
|
||||||
|
endif()
|
||||||
|
|
||||||
set(LDC_LINK_MANUALLY OFF)
|
set(LDC_LINK_MANUALLY OFF)
|
||||||
if(UNIX AND (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")))
|
if(UNIX AND (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")))
|
||||||
# On Unix-like systems, DMD and LDC will use the C compiler for linking, but
|
# On Unix-like systems, DMD and LDC will use the C compiler for linking, but
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "driver/exe_path.h"
|
#include "driver/exe_path.h"
|
||||||
#include "driver/ldc-version.h"
|
#include "driver/ldc-version.h"
|
||||||
#include "driver/linker.h"
|
#include "driver/linker.h"
|
||||||
|
#include "driver/plugins.h"
|
||||||
#include "driver/targetmachine.h"
|
#include "driver/targetmachine.h"
|
||||||
#include "gen/cl_helpers.h"
|
#include "gen/cl_helpers.h"
|
||||||
#include "gen/irstate.h"
|
#include "gen/irstate.h"
|
||||||
|
@ -1063,6 +1064,8 @@ int cppmain(int argc, char **argv) {
|
||||||
opts::initializeInstrumentationOptionsFromCmdline(
|
opts::initializeInstrumentationOptionsFromCmdline(
|
||||||
*global.params.targetTriple);
|
*global.params.targetTriple);
|
||||||
|
|
||||||
|
loadAllPlugins();
|
||||||
|
|
||||||
Strings libmodules;
|
Strings libmodules;
|
||||||
return mars_mainBody(files, libmodules);
|
return mars_mainBody(files, libmodules);
|
||||||
}
|
}
|
||||||
|
|
48
driver/plugins.cpp
Normal file
48
driver/plugins.cpp
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
//===-- driver/plugins.cpp -------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// LDC – the LLVM D compiler
|
||||||
|
//
|
||||||
|
// This file is distributed under the BSD-style LDC license. See the LICENSE
|
||||||
|
// file for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Implements functionality related to plugins (`-plugin=...`).
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "driver/plugins.h"
|
||||||
|
|
||||||
|
#if LDC_ENABLE_PLUGINS
|
||||||
|
|
||||||
|
#include "errors.h"
|
||||||
|
#include "llvm/Support/CommandLine.h"
|
||||||
|
#include "llvm/Support/DynamicLibrary.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
namespace cl = llvm::cl;
|
||||||
|
|
||||||
|
cl::list<std::string>
|
||||||
|
pluginFiles("plugin", cl::CommaSeparated, cl::desc("Plugins to load."),
|
||||||
|
cl::value_desc("<dynamic_library.so, lib2.so>"));
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
/// Loads all plugins. The static constructor of each plugin should take care of
|
||||||
|
/// the plugins registering themself with the rest of LDC/LLVM.
|
||||||
|
void loadAllPlugins() {
|
||||||
|
for (auto &filename : pluginFiles) {
|
||||||
|
std::string errorString;
|
||||||
|
if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(filename.c_str(),
|
||||||
|
&errorString)) {
|
||||||
|
error(Loc(), "Error loading plugin '%s': %s", filename.c_str(),
|
||||||
|
errorString.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // #if LDC_ENABLE_PLUGINS
|
||||||
|
|
||||||
|
void loadAllPlugins() {}
|
||||||
|
|
||||||
|
#endif // LDC_ENABLE_PLUGINS
|
15
driver/plugins.h
Normal file
15
driver/plugins.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
//===-- driver/plugins.h ---------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// LDC – the LLVM D compiler
|
||||||
|
//
|
||||||
|
// This file is distributed under the BSD-style LDC license. See the LICENSE
|
||||||
|
// file for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LDC_DRIVER_PLUGINS_H
|
||||||
|
#define LDC_DRIVER_PLUGINS_H
|
||||||
|
|
||||||
|
void loadAllPlugins();
|
||||||
|
|
||||||
|
#endif // LDC_DRIVER_PLUGINS_H
|
|
@ -22,6 +22,7 @@ config.llvm_targetsstr = "@LLVM_TARGETS_TO_BUILD@"
|
||||||
config.default_target_bits = @DEFAULT_TARGET_BITS@
|
config.default_target_bits = @DEFAULT_TARGET_BITS@
|
||||||
config.with_PGO = True
|
config.with_PGO = True
|
||||||
config.dynamic_compile = @LDC_DYNAMIC_COMPILE@
|
config.dynamic_compile = @LDC_DYNAMIC_COMPILE@
|
||||||
|
config.plugins_supported = "@LDC_ENABLE_PLUGINS@" == "ON"
|
||||||
|
|
||||||
config.name = 'LDC'
|
config.name = 'LDC'
|
||||||
|
|
||||||
|
|
28
tests/plugins/addFuncEntryCall/Makefile
Normal file
28
tests/plugins/addFuncEntryCall/Makefile
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
# ROOT_DIR = directory where Makefile sits
|
||||||
|
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||||
|
ROOT_DIR := $(dir $(MAKEFILE_PATH))
|
||||||
|
|
||||||
|
LLVM_CONFIG ?= llvm-config
|
||||||
|
|
||||||
|
CXXFLAGS ?= -O3
|
||||||
|
CXXFLAGS += $(shell $(LLVM_CONFIG) --cxxflags) -fno-rtti -fpic
|
||||||
|
# Remove all warning flags (they may or may not be supported by the compiler)
|
||||||
|
CXXFLAGS := $(filter-out -W%,$(CXXFLAGS))
|
||||||
|
CXXFLAGS := $(filter-out -fcolor-diagnostics,$(CXXFLAGS))
|
||||||
|
|
||||||
|
ifeq "$(shell uname)" "Darwin"
|
||||||
|
CXXFLAGS += -Wl,-flat_namespace -Wl,-undefined,suppress
|
||||||
|
endif
|
||||||
|
|
||||||
|
PASSLIB = addFuncEntryCallPass
|
||||||
|
|
||||||
|
all: $(PASSLIB)
|
||||||
|
|
||||||
|
$(PASSLIB): $(ROOT_DIR)$(PASSLIB).cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -shared $< -o $@.so
|
||||||
|
|
||||||
|
.NOTPARALLEL: clean
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(PASSLIB).so
|
60
tests/plugins/addFuncEntryCall/addFuncEntryCallPass.cpp
Normal file
60
tests/plugins/addFuncEntryCall/addFuncEntryCallPass.cpp
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
//===-- addFuncEntryCallPass.cpp - Optimize druntime calls ----------------===//
|
||||||
|
//
|
||||||
|
// LDC – the LLVM D compiler
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See the LICENSE file for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "llvm/Pass.h"
|
||||||
|
#include "llvm/IR/Function.h"
|
||||||
|
#include "llvm/IR/IRBuilder.h"
|
||||||
|
#include "llvm/IR/LegacyPassManager.h"
|
||||||
|
#include "llvm/IR/Module.h"
|
||||||
|
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class FuncEntryCallPass : public FunctionPass {
|
||||||
|
|
||||||
|
Constant *funcToCallUponEntry = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static char ID;
|
||||||
|
FuncEntryCallPass() : FunctionPass(ID) {}
|
||||||
|
|
||||||
|
bool doInitialization(Module &M) override;
|
||||||
|
bool runOnFunction(Function &F) override;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
char FuncEntryCallPass::ID = 0;
|
||||||
|
|
||||||
|
bool FuncEntryCallPass::doInitialization(Module &M) {
|
||||||
|
// Add fwd declaration of the `void __test_funcentrycall(void)` function.
|
||||||
|
auto functionType = FunctionType::get(Type::getVoidTy(M.getContext()), false);
|
||||||
|
funcToCallUponEntry =
|
||||||
|
M.getOrInsertFunction("__test_funcentrycall", functionType);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FuncEntryCallPass::runOnFunction(Function &F) {
|
||||||
|
// Add call to `__test_funcentrycall(void)` at the start of _every_ function
|
||||||
|
// (this includes e.g. `ldc.register_dso`!)
|
||||||
|
llvm::BasicBlock &block = F.getEntryBlock();
|
||||||
|
IRBuilder<> builder(&block, block.begin());
|
||||||
|
builder.CreateCall(funcToCallUponEntry);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addFuncEntryCallPass(const PassManagerBuilder &,
|
||||||
|
legacy::PassManagerBase &PM) {
|
||||||
|
PM.add(new FuncEntryCallPass());
|
||||||
|
}
|
||||||
|
// Registration of the plugin's pass is done by the plugin's static constructor.
|
||||||
|
static RegisterStandardPasses
|
||||||
|
RegisterFuncEntryCallPass0(PassManagerBuilder::EP_EnabledOnOptLevel0,
|
||||||
|
addFuncEntryCallPass);
|
14
tests/plugins/addFuncEntryCall/testPlugin.d
Normal file
14
tests/plugins/addFuncEntryCall/testPlugin.d
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// REQUIRES: Plugins
|
||||||
|
|
||||||
|
// RUN: make -f %S/Makefile
|
||||||
|
// RUN: %ldc -c -output-ll -plugin=./addFuncEntryCallPass.so -of=%t.ll %s
|
||||||
|
// RUN: FileCheck %s < %t.ll
|
||||||
|
|
||||||
|
// CHECK: define {{.*}}testfunction
|
||||||
|
int testfunction(int i)
|
||||||
|
{
|
||||||
|
// CHECK-NEXT: call {{.*}}__test_funcentrycall
|
||||||
|
return i * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: declare {{.*}}__test_funcentrycall
|
7
tests/plugins/lit.local.cfg
Normal file
7
tests/plugins/lit.local.cfg
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import re
|
||||||
|
|
||||||
|
if (config.plugins_supported):
|
||||||
|
config.available_features.add('Plugins')
|
||||||
|
config.environment['LLVM_CONFIG'] = os.path.join(config.llvm_tools_dir, 'llvm-config')
|
Loading…
Add table
Add a link
Reference in a new issue