[PECOFF] Define implicit symbols for exported ones.
This patch is to fix a compatibility issue with MSVC link.exe as to
use of dllexported symbols inside DLL.
A DLL exports two symbols for a function. One is non-decorated one,
and the other is with __imp_ prefix. The former is a function that
you can directly call, and the latter is a pointer to the function.
These dllexported symbols are created by linker for programs that
link against the DLL. So, I naturally believed that __imp_ symbols
become available when you once create a DLL and link against it, but
they don't exist until then. And that's not true.
MSVC link.exe is smart enough to allow users to use __imp_ symbols
locally. That is, if a symbol is specified with /export option, it
implicitly creates a new symbol with __imp_ prefix as a pointer to
the exported symbol. This feature allows the following program to
be linked and run, although _imp__hello is not defined in this code.
#include <stdio.h>
__declspec(dllexport)
void hello(void) { printf("Hello\n"); }
extern void (*_imp__hello)(void);
int main() {
_imp__hello();
return 0;
}
MSVC link.exe prints out the following warning when linking it.
LNK4217: locally defined symbol _hello imported in function _main
Using __imp_ symbols locally is I think not a good coding style. One
should just take an address using "&" operator rather than appending
__imp_ prefix. However, there are programs in the wild that depends
on this link.exe's behavior, so we need this feature.
llvm-svn: 207141
This commit is contained in:
parent
b83dd55eb6
commit
f550eba39c
|
|
@ -11,10 +11,25 @@
|
|||
|
||||
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
|
||||
#include "lld/ReaderWriter/Simple.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
|
||||
namespace lld {
|
||||
namespace pecoff {
|
||||
|
||||
/// The defined atom for dllexported symbols with __imp_ prefix.
|
||||
class ImpPointerAtom : public COFFLinkerInternalAtom {
|
||||
public:
|
||||
ImpPointerAtom(const File &file, StringRef symbolName)
|
||||
: COFFLinkerInternalAtom(file, /*oridnal*/ 0, std::vector<uint8_t>(4),
|
||||
symbolName) {}
|
||||
|
||||
uint64_t ordinal() const override { return 0; }
|
||||
Scope scope() const override { return scopeGlobal; }
|
||||
ContentType contentType() const override { return typeData; }
|
||||
Alignment alignment() const override { return Alignment(4); }
|
||||
ContentPermissions permissions() const override { return permR__; }
|
||||
};
|
||||
|
||||
// A virtual file containing absolute symbol __ImageBase. __ImageBase (or
|
||||
// ___ImageBase on x86) is a linker-generated symbol whose address is the same
|
||||
// as the image base address.
|
||||
|
|
@ -25,10 +40,29 @@ public:
|
|||
_imageBaseAtom(*this, ctx.decorateSymbol("__ImageBase"),
|
||||
Atom::scopeGlobal, ctx.getBaseAddress()) {
|
||||
addAtom(_imageBaseAtom);
|
||||
|
||||
// Create implciit symbols for exported symbols.
|
||||
for (const PECOFFLinkingContext::ExportDesc exp : ctx.getDllExports()) {
|
||||
UndefinedAtom *target = new (_alloc) SimpleUndefinedAtom(*this, exp.name);
|
||||
COFFLinkerInternalAtom *imp = createImpPointerAtom(ctx, exp.name);
|
||||
imp->addReference(std::unique_ptr<COFFReference>(
|
||||
new COFFReference(target, 0, llvm::COFF::IMAGE_REL_I386_DIR32)));
|
||||
addAtom(*target);
|
||||
addAtom(*imp);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
COFFLinkerInternalAtom *createImpPointerAtom(const PECOFFLinkingContext &ctx,
|
||||
StringRef name) {
|
||||
std::string sym = "_imp_";
|
||||
sym.append(name);
|
||||
sym = ctx.decorateSymbol(sym);
|
||||
return new (_alloc) ImpPointerAtom(*this, ctx.allocate(sym));
|
||||
}
|
||||
|
||||
COFFAbsoluteAtom _imageBaseAtom;
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
} // end namespace pecoff
|
||||
|
|
|
|||
Loading…
Reference in New Issue