mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-08 20:06:03 +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-msvc.cpp
|
||||
driver/main.cpp
|
||||
driver/plugins.cpp
|
||||
${CMAKE_BINARY_DIR}/driver/ldc-version.cpp
|
||||
)
|
||||
set(DRV_HDR
|
||||
|
@ -337,6 +338,7 @@ set(DRV_HDR
|
|||
driver/ldc-version.h
|
||||
driver/archiver.h
|
||||
driver/linker.h
|
||||
driver/plugins.h
|
||||
driver/targetmachine.h
|
||||
driver/toobj.h
|
||||
driver/tool.h
|
||||
|
@ -559,6 +561,24 @@ if(LDC_WITH_LLD)
|
|||
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)
|
||||
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
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "driver/exe_path.h"
|
||||
#include "driver/ldc-version.h"
|
||||
#include "driver/linker.h"
|
||||
#include "driver/plugins.h"
|
||||
#include "driver/targetmachine.h"
|
||||
#include "gen/cl_helpers.h"
|
||||
#include "gen/irstate.h"
|
||||
|
@ -1063,6 +1064,8 @@ int cppmain(int argc, char **argv) {
|
|||
opts::initializeInstrumentationOptionsFromCmdline(
|
||||
*global.params.targetTriple);
|
||||
|
||||
loadAllPlugins();
|
||||
|
||||
Strings 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.with_PGO = True
|
||||
config.dynamic_compile = @LDC_DYNAMIC_COMPILE@
|
||||
config.plugins_supported = "@LDC_ENABLE_PLUGINS@" == "ON"
|
||||
|
||||
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