Skip to content

Commit

Permalink
[X86-64] Don't initialize externally defined variables
Browse files Browse the repository at this point in the history
At present, external variables such as stdout, stderr, ... are
incorrectly treated as local variables initialized to 0. With
this change references to such external variables are correctly
emited as external variables with no need to be initialized to 0.

[NFC] Renamed
      - files ExternalFunctions.* to IncludeFileInfo.*
      - class ExternalFunctions to IncludeFileInfo
      - static member fields of the class as appropriate.

[Test] Added test to verify reference to externally defined variables.
  • Loading branch information
martin-fink authored and bharadwajy committed Sep 7, 2021
1 parent d8d8549 commit b09192e
Show file tree
Hide file tree
Showing 12 changed files with 114 additions and 50 deletions.
4 changes: 2 additions & 2 deletions ARM/ARMMIRevising.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include "ARMMIRevising.h"
#include "ARMModuleRaiser.h"
#include "ARMSubtarget.h"
#include "ExternalFunctions.h"
#include "IncludedFileInfo.h"
#include "MCInstRaiser.h"
#include "MachineFunctionRaiser.h"
#include "llvm/BinaryFormat/ELF.h"
Expand Down Expand Up @@ -169,7 +169,7 @@ uint64_t ARMMIRevising::getCalledFunctionAtPLTOffset(uint64_t PLTEndOff,
// Set CallTargetIndex for plt offset to map undefined function symbol
// for emit CallInst use.
Function *CalledFunc =
ExternalFunctions::Create(*CalledFuncSymName, *MR);
IncludedFileInfo::CreateFunction(*CalledFuncSymName, *MR);
// Bail out if function prototype is not available
if (!CalledFunc)
exit(-1);
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ add_subdirectory(test)
add_llvm_tool(llvm-mctoll
llvm-mctoll.cpp
COFFDump.cpp
ExternalFunctions.cpp
IncludedFileInfo.cpp
FunctionFilter.cpp
MachODump.cpp
ModuleRaiser.cpp
Expand Down
2 changes: 1 addition & 1 deletion FunctionFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ FunctionFilter::~FunctionFilter() {
}

/// Get the data type corresponding to type string. These correspond to type
/// strings generated in ExternalFunctions.cpp upon parsing user specified
/// strings generated in IncludedFileInfo.cpp upon parsing user specified
/// include files with external function prototypes.
Type *FunctionFilter::getPrimitiveDataType(const StringRef &TypeStr) {
LLVMContext &CTX = M.getContext();
Expand Down
60 changes: 39 additions & 21 deletions ExternalFunctions.cpp → IncludedFileInfo.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===-- ExternalFunctions.cpp -----------------------------------*- C++ -*-===//
//===-- IncludedFileInfo.cpp -----------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand All @@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//

#include "ExternalFunctions.h"
#include "IncludedFileInfo.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
Expand All @@ -32,8 +32,10 @@
// as Type being used in this file are from clang namespace and not from llvm
// namespace.

std::map<std::string, ExternalFunctions::RetAndArgs>
ExternalFunctions::UserSpecifiedFunctions;
std::map<std::string, IncludedFileInfo::FunctionRetAndArgs>
IncludedFileInfo::ExternalFunctions;

std::set<std::string> IncludedFileInfo::ExternalVariables;

// FuncDeclVisitor

Expand All @@ -46,7 +48,7 @@ class FuncDeclVisitor : public clang::RecursiveASTVisitor<FuncDeclVisitor> {
}

bool VisitFunctionDecl(clang::FunctionDecl *FuncDecl) {
ExternalFunctions::RetAndArgs Entry;
IncludedFileInfo::FunctionRetAndArgs Entry;
clang::QualType RetTy = FuncDecl->getDeclaredReturnType();
Entry.ReturnType =
getUnqualifiedTypeString(RetTy, FuncDecl->getASTContext());
Expand All @@ -62,17 +64,17 @@ class FuncDeclVisitor : public clang::RecursiveASTVisitor<FuncDeclVisitor> {
// function name to detect duplicate function prototype specification. Need
// to update this check to include argument types when support to raise C++
// binary is added.
if (ExternalFunctions::UserSpecifiedFunctions.find(
if (IncludedFileInfo::ExternalFunctions.find(
FuncDecl->getQualifiedNameAsString()) !=
ExternalFunctions::UserSpecifiedFunctions.end()) {
IncludedFileInfo::ExternalFunctions.end()) {
LLVM_DEBUG(dbgs() << FuncDecl->getQualifiedNameAsString()
<< " : Ignoring duplicate entry at "
<< FuncDecl->getLocation().printToString(
Context.getSourceManager())
<< "\n");
} else {
ExternalFunctions::UserSpecifiedFunctions.insert(
std::pair<std::string, ExternalFunctions::RetAndArgs>(
IncludedFileInfo::ExternalFunctions.insert(
std::pair<std::string, IncludedFileInfo::FunctionRetAndArgs>(
FuncDecl->getQualifiedNameAsString(), Entry));
LLVM_DEBUG(dbgs() << FuncDecl->getQualifiedNameAsString()
<< " : Entry found at "
Expand Down Expand Up @@ -161,13 +163,17 @@ class FuncDeclFinder : public clang::ASTConsumer {
auto Decls = Context.getTranslationUnitDecl()->decls();
clang::SourceManager &SourceManager(Context.getSourceManager());
for (auto &Decl : Decls) {
if (!Decl->isFunctionOrFunctionTemplate())
continue;
const auto &FileID = SourceManager.getFileID(Decl->getLocation());
if (FileID != SourceManager.getMainFileID())
continue;
clang::FunctionDecl *FuncDecl = Decl->getAsFunction();
Visitor.TraverseFunctionDecl(FuncDecl);
if (Decl->isFunctionOrFunctionTemplate()) {
const auto &FileID = SourceManager.getFileID(Decl->getLocation());
if (FileID != SourceManager.getMainFileID())
continue;
clang::FunctionDecl *FuncDecl = Decl->getAsFunction();
Visitor.TraverseFunctionDecl(FuncDecl);
} else if (Decl->getKind() == clang::Decl::Kind::Var) {
auto VarDecl = dyn_cast<clang::VarDecl>(Decl);
IncludedFileInfo::ExternalVariables.insert(
VarDecl->getQualifiedNameAsString());
}
}
}
};
Expand All @@ -183,23 +189,23 @@ class FuncDeclFindingAction : public clang::ASTFrontendAction {
};

// Construct and return a Function* corresponding to a known external function
Function *ExternalFunctions::Create(StringRef &CFuncName, ModuleRaiser &MR) {
Function *IncludedFileInfo::CreateFunction(StringRef &CFuncName, ModuleRaiser &MR) {
Module *M = MR.getModule();
assert(M != nullptr && "Uninitialized ModuleRaiser!");

Function *Func = M->getFunction(CFuncName);
if (Func != nullptr)
return Func;

auto iter = ExternalFunctions::UserSpecifiedFunctions.find(CFuncName.str());
if (iter == ExternalFunctions::UserSpecifiedFunctions.end()) {
auto iter = IncludedFileInfo::ExternalFunctions.find(CFuncName.str());
if (iter == IncludedFileInfo::ExternalFunctions.end()) {
errs() << "Unknown prototype for function : " << CFuncName.data() << "\n";
errs() << "Use -I </full/path/to/file>, where /full/path/to/file declares "
"its prototype\n";
return nullptr;
}

const ExternalFunctions::RetAndArgs &retAndArgs = iter->second;
const IncludedFileInfo::FunctionRetAndArgs &retAndArgs = iter->second;
Type *RetType =
MR.getFunctionFilter()->getPrimitiveDataType(retAndArgs.ReturnType);
std::vector<Type *> ArgVec;
Expand Down Expand Up @@ -227,7 +233,7 @@ Function *ExternalFunctions::Create(StringRef &CFuncName, ModuleRaiser &MR) {
return nullptr;
}

bool ExternalFunctions::getUserSpecifiedFuncPrototypes(
bool IncludedFileInfo::getExternalFunctionPrototype(
std::vector<std::string> &FileNames, std::string &CompDBDir) {
static llvm::cl::OptionCategory InclFileParseCategory(
"parse-header-files options");
Expand Down Expand Up @@ -276,4 +282,16 @@ bool ExternalFunctions::getUserSpecifiedFuncPrototypes(
return true;
}

bool IncludedFileInfo::IsExternalVariable(std::string Name) {
// If there is a suffix like stdout@@GLIBC_2.2.5, remove it to check
// if the symbol is defined in a user-passed header file
auto NameEnd = Name.find("@@");
if (NameEnd != std::string::npos) {
Name = Name.substr(0, NameEnd);
}
// Declare external global variables as external and don't initalize them
return IncludedFileInfo::ExternalVariables.find(Name) !=
IncludedFileInfo::ExternalVariables.end();
}

#undef DEBUG_TYPE
31 changes: 18 additions & 13 deletions ExternalFunctions.h → IncludedFileInfo.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===-- ExternalFunctions.h -------------------------------------*- C++ -*-===//
//===-- IncludedFileInfo.h -------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand All @@ -10,32 +10,37 @@
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TOOLS_LLVM_MCTOLL_EXTERNALFUNCTIONS_H
#define LLVM_TOOLS_LLVM_MCTOLL_EXTERNALFUNCTIONS_H
#ifndef LLVM_TOOLS_LLVM_MCTOLL_INCLUDEDFILEINFO_H
#define LLVM_TOOLS_LLVM_MCTOLL_INCLUDEDFILEINFO_H

#include "ModuleRaiser.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"

using namespace llvm;

class ExternalFunctions {
ExternalFunctions(){};
~ExternalFunctions(){};
class IncludedFileInfo {
IncludedFileInfo(){};
~IncludedFileInfo(){};

public:
typedef struct RetAndArgs_t {
typedef struct FunctionRetAndArgs_t {
std::string ReturnType;
std::vector<std::string> Arguments;
bool isVariadic;
} RetAndArgs;
} FunctionRetAndArgs;

static Function *CreateFunction(StringRef &CFuncName, ModuleRaiser &MR);

static Function *Create(StringRef &CFuncName, ModuleRaiser &MR);
// Table of user specified function prototypes
static std::map<std::string, ExternalFunctions::RetAndArgs>
UserSpecifiedFunctions;
static bool getUserSpecifiedFuncPrototypes(std::vector<string> &FileNames,
static std::map<std::string, IncludedFileInfo::FunctionRetAndArgs> ExternalFunctions;

static std::set<std::string> ExternalVariables;

static bool getExternalFunctionPrototype(std::vector<string> &FileNames,
std::string &CompDBDir);

static bool IsExternalVariable(std::string Name);
};

#endif // LLVM_TOOLS_LLVM_MCTOLL_EXTERNALFUNCTIONS_H
#endif // LLVM_TOOLS_LLVM_MCTOLL_INCLUDEDFILEINFO_H
2 changes: 1 addition & 1 deletion RISCV/RISCV32MachineInstructionRaiser.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "ExternalFunctions.h"
#include "IncludedFileInfo.h"
#include "MachineFunctionRaiser.h"
#include "RISCV32ModuleRaiser.h"
#include "llvm-mctoll.h"
Expand Down
2 changes: 1 addition & 1 deletion X86/X86FuncPrototypeDiscovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//

#include "ExternalFunctions.h"
#include "IncludedFileInfo.h"
#include "MachineFunctionRaiser.h"
#include "X86InstrBuilder.h"
#include "X86MachineInstructionRaiser.h"
Expand Down
2 changes: 1 addition & 1 deletion X86/X86MachineInstructionRaiser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//

#include "X86MachineInstructionRaiser.h"
#include "ExternalFunctions.h"
#include "IncludedFileInfo.h"
#include "MachineFunctionRaiser.h"
#include "X86InstrBuilder.h"
#include "X86ModuleRaiser.h"
Expand Down
2 changes: 1 addition & 1 deletion X86/X86MachineInstructionRaiserSSE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//

#include "ExternalFunctions.h"
#include "IncludedFileInfo.h"
#include "X86MachineInstructionRaiser.h"
#include "X86RaisedValueTracker.h"
#include "X86RegisterUtils.h"
Expand Down
34 changes: 28 additions & 6 deletions X86/X86MachineInstructionRaiserUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//

#include "ExternalFunctions.h"
#include "IncludedFileInfo.h"
#include "InstMetadata.h"
#include "X86MachineInstructionRaiser.h"
#include "X86RaisedValueTracker.h"
Expand Down Expand Up @@ -745,9 +745,17 @@ Value *X86MachineInstructionRaiser::createPCRelativeAccesssValue(
break;
}
}
Constant *GlobalInit = (DynRelocType == ELF::R_X86_64_GLOB_DAT)
? ConstantInt::get(GlobalValTy, SymbVal)
: nullptr;

Constant *GlobalInit;
if (IncludedFileInfo::IsExternalVariable(Symname->str())) {
GlobalInit = nullptr;
Lnkg = GlobalValue::ExternalLinkage;
} else {
GlobalInit = (DynRelocType == ELF::R_X86_64_GLOB_DAT)
? ConstantInt::get(GlobalValTy, SymbVal)
: nullptr;
}

auto GlobalVal = new GlobalVariable(*(MR->getModule()), GlobalValTy,
false /* isConstant */, Lnkg,
GlobalInit, Symname->data());
Expand Down Expand Up @@ -859,7 +867,14 @@ Value *X86MachineInstructionRaiser::createPCRelativeAccesssValue(
assert(false && "Unexpected symbol size");
}

Constant *GlobalInit = ConstantInt::get(GlobalValTy, SymInitVal);
Constant *GlobalInit;
if (IncludedFileInfo::IsExternalVariable(Symname->str())) {
GlobalInit = nullptr;
Lnkg = GlobalValue::ExternalLinkage;
} else {
GlobalInit = ConstantInt::get(GlobalValTy, SymInitVal);
}

auto GlobalVal = new GlobalVariable(*(MR->getModule()), GlobalValTy,
false /* isConstant */, Lnkg,
GlobalInit, Symname->data());
Expand Down Expand Up @@ -1488,7 +1503,7 @@ Function *X86MachineInstructionRaiser::getTargetFunctionAtPLTOffset(
// This is an undefined function symbol. Look through the list of
// user provided function prototypes and construct a Function
// accordingly.
CalledFunc = ExternalFunctions::Create(*CalledFuncSymName,
CalledFunc = IncludedFileInfo::CreateFunction(*CalledFuncSymName,
*const_cast<ModuleRaiser *>(MR));
// Bail out if function prototype is not available
if (!CalledFunc)
Expand Down Expand Up @@ -1864,6 +1879,13 @@ X86MachineInstructionRaiser::getGlobalVariableValueAt(const MachineInstr &MI,
GlobalInit = ConstantInt::get(GlobalValTy, SV);
}

// Declare external global variables as external and don't initalize them
if (IncludedFileInfo::IsExternalVariable(
GlobalDataSymNameIndexStrRef.str())) {
Lnkg = GlobalValue::ExternalLinkage;
GlobalInit = nullptr;
}

// Now, create the global variable for the symbol at given Offset.
auto GlobalVal = new GlobalVariable(
*(MR->getModule()), GlobalValTy, false /* isConstant */, Lnkg,
Expand Down
4 changes: 2 additions & 2 deletions llvm-mctoll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

#include "llvm-mctoll.h"
#include "EmitRaisedOutputPass.h"
#include "ExternalFunctions.h"
#include "IncludedFileInfo.h"
#include "MCInstOrData.h"
#include "MachineFunctionRaiser.h"
#include "ModuleRaiser.h"
Expand Down Expand Up @@ -1603,7 +1603,7 @@ int main(int argc, char **argv) {
std::vector<string> InclFNames(InclFNameSet.begin(), InclFNameSet.end());

if (!InclFNames.empty()) {
if (!ExternalFunctions::getUserSpecifiedFuncPrototypes(InclFNames,
if (!IncludedFileInfo::getExternalFunctionPrototype(InclFNames,
CompilationDBDir)) {
dbgs() << "Unable to read external function prototype. Ignoring\n";
}
Expand Down
19 changes: 19 additions & 0 deletions test/smoke_test/fprintf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// REQUIRES: system-linux
// RUN: clang -o %t %s
// RUN: llvm-mctoll -d -I /usr/include/stdio.h %t
// RUN: clang -o %t1 %t-dis.ll
// RUN: %t1 2>&1 | FileCheck %s
// CHECK: x = 0, y = 0, z = 1
// CHECK-EMPTY

#include <stdio.h>

int x;
int y = 0;
int z = 1;

int main() {
fprintf(stdout, "x = %d, y = %d, z = %d\n", x, y, z);

return 0;
}

0 comments on commit b09192e

Please sign in to comment.