<rdar://problem/6927148> libLTO needs to handle i386 magic objc class symbols

Parse __OBJC data structures and synthesize magic .objc_ symbols.
Also, alter mangler so that objc method names are readable.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@72700 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Nick Kledzik 2009-06-01 20:33:09 +00:00
parent 8fff19ba55
commit 3eb445feb2
2 changed files with 152 additions and 18 deletions

View File

@ -14,6 +14,7 @@
#include "LTOModule.h"
#include "llvm/Constants.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/ADT/OwningPtr.h"
@ -176,11 +177,123 @@ void LTOModule::addDefinedFunctionSymbol(Function* f, Mangler &mangler)
}
}
void LTOModule::addDefinedDataSymbol(GlobalValue* v, Mangler &mangler)
// get string that data pointer points to
bool LTOModule::objcClassNameFromExpression(Constant* c, std::string& name)
{
if (ConstantExpr* ce = dyn_cast<ConstantExpr>(c)) {
Constant* op = ce->getOperand(0);
if (GlobalVariable* gvn = dyn_cast<GlobalVariable>(op)) {
Constant* cn = gvn->getInitializer();
if (ConstantArray* ca = dyn_cast<ConstantArray>(cn)) {
if ( ca->isCString() ) {
name = ".objc_class_name_" + ca->getAsString();
return true;
}
}
}
}
return false;
}
// parse i386/ppc ObjC class data structure
void LTOModule::addObjCClass(GlobalVariable* clgv)
{
if (ConstantStruct* c = dyn_cast<ConstantStruct>(clgv->getInitializer())) {
// second slot in __OBJC,__class is pointer to superclass name
std::string superclassName;
if ( objcClassNameFromExpression(c->getOperand(1), superclassName) ) {
NameAndAttributes info;
if ( _undefines.find(superclassName.c_str()) == _undefines.end() ) {
const char* symbolName = ::strdup(superclassName.c_str());
info.name = ::strdup(symbolName);
info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED;
// string is owned by _undefines
_undefines[info.name] = info;
}
}
// third slot in __OBJC,__class is pointer to class name
std::string className;
if ( objcClassNameFromExpression(c->getOperand(2), className) ) {
const char* symbolName = ::strdup(className.c_str());
NameAndAttributes info;
info.name = symbolName;
info.attributes = (lto_symbol_attributes)
(LTO_SYMBOL_PERMISSIONS_DATA |
LTO_SYMBOL_DEFINITION_REGULAR |
LTO_SYMBOL_SCOPE_DEFAULT);
_symbols.push_back(info);
_defines[info.name] = 1;
}
}
}
// parse i386/ppc ObjC category data structure
void LTOModule::addObjCCategory(GlobalVariable* clgv)
{
if (ConstantStruct* c = dyn_cast<ConstantStruct>(clgv->getInitializer())) {
// second slot in __OBJC,__category is pointer to target class name
std::string targetclassName;
if ( objcClassNameFromExpression(c->getOperand(1), targetclassName) ) {
NameAndAttributes info;
if ( _undefines.find(targetclassName.c_str()) == _undefines.end() ){
const char* symbolName = ::strdup(targetclassName.c_str());
info.name = ::strdup(symbolName);
info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED;
// string is owned by _undefines
_undefines[info.name] = info;
}
}
}
}
// parse i386/ppc ObjC class list data structure
void LTOModule::addObjCClassRef(GlobalVariable* clgv)
{
std::string targetclassName;
if ( objcClassNameFromExpression(clgv->getInitializer(), targetclassName) ){
NameAndAttributes info;
if ( _undefines.find(targetclassName.c_str()) == _undefines.end() ) {
const char* symbolName = ::strdup(targetclassName.c_str());
info.name = ::strdup(symbolName);
info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED;
// string is owned by _undefines
_undefines[info.name] = info;
}
}
}
void LTOModule::addDefinedDataSymbol(GlobalValue* v, Mangler& mangler)
{
// add to list of defined symbols
addDefinedSymbol(v, mangler, false);
// special case i386/ppc ObjC data structures in magic sections
if ( v->hasSection() ) {
// special case if this data blob is an ObjC class definition
if ( v->getSection().compare(0, 15, "__OBJC,__class,") == 0 ) {
if (GlobalVariable* gv = dyn_cast<GlobalVariable>(v)) {
addObjCClass(gv);
}
}
// special case if this data blob is an ObjC category definition
else if ( v->getSection().compare(0, 18, "__OBJC,__category,") == 0 ) {
if (GlobalVariable* gv = dyn_cast<GlobalVariable>(v)) {
addObjCCategory(gv);
}
}
// special case if this data blob is the list of referenced classes
else if ( v->getSection().compare(0, 18, "__OBJC,__cls_refs,") == 0 ) {
if (GlobalVariable* gv = dyn_cast<GlobalVariable>(v)) {
addObjCClassRef(gv);
}
}
}
// add external symbols referenced by this data.
for (unsigned count = 0, total = v->getNumOperands();
count != total; ++count) {
@ -192,9 +305,13 @@ void LTOModule::addDefinedDataSymbol(GlobalValue* v, Mangler &mangler)
void LTOModule::addDefinedSymbol(GlobalValue* def, Mangler &mangler,
bool isFunction)
{
// ignore all llvm.* symbols
if ( strncmp(def->getNameStart(), "llvm.", 5) == 0 )
return;
// string is owned by _defines
const char* symbolName = ::strdup(mangler.getValueName(def).c_str());
// set alignment part log2() can have rounding errors
uint32_t align = def->getAlignment();
uint32_t attr = align ? CountTrailingZeros_32(def->getAlignment()) : 0;
@ -241,25 +358,28 @@ void LTOModule::addDefinedSymbol(GlobalValue* def, Mangler &mangler,
}
void LTOModule::addAsmGlobalSymbol(const char *name) {
// string is owned by _defines
const char *symbolName = ::strdup(name);
uint32_t attr = LTO_SYMBOL_DEFINITION_REGULAR;
attr |= LTO_SYMBOL_SCOPE_DEFAULT;
// add to table of symbols
NameAndAttributes info;
info.name = symbolName;
info.attributes = (lto_symbol_attributes)attr;
_symbols.push_back(info);
_defines[info.name] = 1;
// only add new define if not already defined
if ( _defines.count(name, &name[strlen(name)+1]) == 0 )
return;
// string is owned by _defines
const char *symbolName = ::strdup(name);
uint32_t attr = LTO_SYMBOL_DEFINITION_REGULAR;
attr |= LTO_SYMBOL_SCOPE_DEFAULT;
NameAndAttributes info;
info.name = symbolName;
info.attributes = (lto_symbol_attributes)attr;
_symbols.push_back(info);
_defines[info.name] = 1;
}
void LTOModule::addPotentialUndefinedSymbol(GlobalValue* decl, Mangler &mangler)
{
const char* name = mangler.getValueName(decl).c_str();
// ignore all llvm.* symbols
if ( strncmp(name, "llvm.", 5) == 0 )
return;
if ( strncmp(decl->getNameStart(), "llvm.", 5) == 0 )
return;
const char* name = mangler.getValueName(decl).c_str();
// we already have the symbol
if (_undefines.find(name) != _undefines.end())
@ -306,6 +426,14 @@ void LTOModule::lazyParseSymbols()
// Use mangler to add GlobalPrefix to names to match linker names.
Mangler mangler(*_module, _target->getTargetAsmInfo()->getGlobalPrefix());
// add chars used in ObjC method names so method names aren't mangled
mangler.markCharAcceptable('[');
mangler.markCharAcceptable(']');
mangler.markCharAcceptable('(');
mangler.markCharAcceptable(')');
mangler.markCharAcceptable('-');
mangler.markCharAcceptable('+');
mangler.markCharAcceptable(' ');
// add functions
for (Module::iterator f = _module->begin(); f != _module->end(); ++f) {

View File

@ -77,13 +77,19 @@ private:
void addDefinedDataSymbol(llvm::GlobalValue* v,
llvm::Mangler &mangler);
void addAsmGlobalSymbol(const char *);
void addObjCClass(llvm::GlobalVariable* clgv);
void addObjCCategory(llvm::GlobalVariable* clgv);
void addObjCClassRef(llvm::GlobalVariable* clgv);
bool objcClassNameFromExpression(llvm::Constant* c,
std::string& name);
static bool isTargetMatch(llvm::MemoryBuffer* memBuffer,
const char* triplePrefix);
static LTOModule* makeLTOModule(llvm::MemoryBuffer* buffer,
std::string& errMsg);
static llvm::MemoryBuffer* makeBuffer(const void* mem, size_t length);
typedef llvm::StringMap<uint8_t> StringSet;
struct NameAndAttributes {