diff options
author | Karl Schimpf <kschimpf@google.com> | 2013-07-02 14:36:36 -0700 |
---|---|---|
committer | Karl Schimpf <kschimpf@google.com> | 2013-07-02 14:36:36 -0700 |
commit | 4390b1a9ac86937b9f9886119b5fa0ffc77295eb (patch) | |
tree | 0ed3cbe3018c87f90bb55627066f6bdd5cfae9e0 | |
parent | bdad02d55969b0963ac23e05578d28def5636ebd (diff) |
Simplify globals in PNaCl wire format based on normalized constants.
Generates simple global variable records, followed by list of records defining
byte initialization and relocations.
BUG= https://code.google.com/p/nativeclient/issues/detail?id=3504
R=mseaborn@chromium.org
Review URL: https://codereview.chromium.org/18111002
-rw-r--r-- | include/llvm/Bitcode/NaCl/NaClLLVMBitCodes.h | 34 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp | 291 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h | 24 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp | 257 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp | 22 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h | 13 | ||||
-rw-r--r-- | test/NaCl/Bitcode/globalvars.ll | 98 | ||||
-rw-r--r-- | tools/pnacl-bcanalyzer/pnacl-bcanalyzer.cpp | 11 |
8 files changed, 573 insertions, 177 deletions
diff --git a/include/llvm/Bitcode/NaCl/NaClLLVMBitCodes.h b/include/llvm/Bitcode/NaCl/NaClLLVMBitCodes.h index f4fc4b8e6f..7d270cd98c 100644 --- a/include/llvm/Bitcode/NaCl/NaClLLVMBitCodes.h +++ b/include/llvm/Bitcode/NaCl/NaClLLVMBitCodes.h @@ -43,7 +43,8 @@ namespace naclbitc { TYPE_BLOCK_ID_NEW, - USELIST_BLOCK_ID + USELIST_BLOCK_ID, + GLOBALVAR_BLOCK_ID }; @@ -58,9 +59,7 @@ namespace naclbitc { // FIXME: Remove DEPLIB in 4.0. MODULE_CODE_DEPLIB = 6, // DEPLIB: [strchr x N] - // GLOBALVAR: [pointer type, isconst, initid, - // linkage, alignment, section, visibility, threadlocal] - MODULE_CODE_GLOBALVAR = 7, + MODULE_CODE_GLOBALVAR = 7, // Not used in PNaCl. // FUNCTION: [type, callingconv, isproto, linkage] MODULE_CODE_FUNCTION = 8, @@ -179,6 +178,33 @@ namespace naclbitc { // asmdialect,asmstr,conststr] }; + /// GlobalVarOpcodes - These are values used in the bitcode files to + /// encode records defining global variables. + /// + /// The structure of global variables can be summarized as follows: + /// + /// The global variable block begins with a GLOBALVAR_COUNT, defining + /// the number of global variables in the bitcode file. After that, + /// each global variable is defined. + /// + /// Global variables are defined by a GLOBALVAR_VAR record, followed + /// by 1 or more records defining its initial value. Simple + /// variables have a single initializer. Structured variables are + /// defined by an initial GLOBALVAR_COMPOUND record defining the + /// number of fields in the structure, followed by an initializer + /// for each of its fields. In this context, a field is either data, + /// or a relocation. A data field is defined by a + /// GLOBALVAR_ZEROFILL or GLOBALVAR_DATA record. A relocation field + /// is defined by a GLOBALVAR_RELOC record. + enum NaClGlobalVarOpcodes { + GLOBALVAR_VAR = 0, // VAR: [align, isconst] + GLOBALVAR_COMPOUND = 1, // COMPOUND: [size] + GLOBALVAR_ZEROFILL = 2, // ZEROFILL: [size] + GLOBALVAR_DATA = 3, // DATA: [b0, b1, ...] + GLOBALVAR_RELOC = 4, // RELOC: [val, [addend]] + GLOBALVAR_COUNT = 5, // COUNT: [n] + }; + /// CastOpcodes - These are values used in the bitcode files to encode which /// cast a CST_CODE_CE_CAST or a XXX refers to. The values of these enums /// have no fixed relation to the LLVM IR enum values. Changing these will diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp index 9f36a73654..5f14a639ba 100644 --- a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp +++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp @@ -101,17 +101,6 @@ static GlobalValue::VisibilityTypes GetDecodedVisibility(unsigned Val) { } } -static GlobalVariable::ThreadLocalMode GetDecodedThreadLocalMode(unsigned Val) { - switch (Val) { - case 0: return GlobalVariable::NotThreadLocal; - default: // Map unknown non-zero value to general dynamic. - case 1: return GlobalVariable::GeneralDynamicTLSModel; - case 2: return GlobalVariable::LocalDynamicTLSModel; - case 3: return GlobalVariable::InitialExecTLSModel; - case 4: return GlobalVariable::LocalExecTLSModel; - } -} - static int GetDecodedCastOpcode(unsigned Val) { switch (Val) { default: return -1; @@ -236,6 +225,7 @@ struct OperandTraits<ConstantPlaceHolder> : void NaClBitcodeReaderValueList::AssignValue(Value *V, unsigned Idx) { + assert(V); if (Idx == size()) { push_back(V); return; @@ -263,9 +253,35 @@ void NaClBitcodeReaderValueList::AssignValue(Value *V, unsigned Idx) { } } +void NaClBitcodeReaderValueList::AssignGlobalVar(GlobalVariable *GV, + unsigned Idx) { + assert(GV); + + if (Idx == size()) { + push_back(GV); + return; + } + + if (Idx >= size()) + resize(Idx+1); + + WeakVH &OldV = ValuePtrs[Idx]; + if (OldV == 0) { + OldV = GV; + return; + } + + // If there was a forward reference to this value, replace it. + Value *PrevVal = OldV; + GlobalVariable *Placeholder = cast<GlobalVariable>(PrevVal); + Placeholder->replaceAllUsesWith( + ConstantExpr::getBitCast(GV, Placeholder->getType())); + Placeholder->eraseFromParent(); + ValuePtrs[Idx] = GV; +} Constant *NaClBitcodeReaderValueList::getConstantFwdRef(unsigned Idx, - Type *Ty) { + Type *Ty) { if (Idx >= size()) resize(Idx + 1); @@ -307,6 +323,26 @@ bool NaClBitcodeReaderValueList::createValueFwdRef(unsigned Idx, Type *Ty) { return false; } +Constant *NaClBitcodeReaderValueList::getOrCreateGlobalVarRef( + unsigned Idx, Module *M) { + // First make sure the element for Idx is defined. + if (Idx >= size()) + resize(Idx + 1); + + // Now get its value (if applicable). + if (Value *V = ValuePtrs[Idx]) + return dyn_cast<Constant>(V); + + // Create a placeholder, which will later be RAUW'd. + Type *PlaceholderType = Type::getInt8Ty(Context); + + Constant *C = + new GlobalVariable(*M, PlaceholderType, false, + GlobalValue::ExternalLinkage, 0); + ValuePtrs[Idx] = C; + return C; +} + /// ResolveConstantForwardRefs - Once all constants are read, this method bulk /// resolves any forward references. The idea behind this is that we sometimes /// get constants (such as large arrays) which reference *many* forward ref @@ -635,6 +671,147 @@ bool NaClBitcodeReader::ParseTypeTableBody() { } } +bool NaClBitcodeReader::ParseGlobalVars() { + if (Stream.EnterSubBlock(naclbitc::GLOBALVAR_BLOCK_ID)) + return Error("Malformed block record"); + + SmallVector<uint64_t, 64> Record; + + // True when processing a global variable. Stays true until all records + // are processed, and the global variable is created. + bool ProcessingGlobal = false; + // The alignment value defined for the global variable. + unsigned VarAlignment = 0; + // True if the variable is read-only. + bool VarIsConstant = false; + // The initializer for the global variable. + SmallVector<Constant *, 10> VarInit; + // The number of initializers needed for the global variable. + unsigned VarInitializersNeeded = 0; + unsigned FirstValueNo = ValueList.size(); + // The index of the next global variable. + unsigned NextValueNo = FirstValueNo; + // The number of expected global variable definitions. + unsigned NumGlobals = 0; + + // Read all global variable records. + while (1) { + NaClBitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + switch (Entry.Kind) { + case NaClBitstreamEntry::SubBlock: + case NaClBitstreamEntry::Error: + return Error("Error in the global vars block"); + case NaClBitstreamEntry::EndBlock: + if (ProcessingGlobal || NumGlobals != (NextValueNo - FirstValueNo)) + return Error("Error in the global vars block"); + return false; + case NaClBitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + Record.clear(); + unsigned Bitcode = Stream.readRecord(Entry.ID, Record); + switch (Bitcode) { + default: return Error("Unknown global variable entry"); + case naclbitc::GLOBALVAR_VAR: + // Start the definition of a global variable. + if (ProcessingGlobal || Record.size() != 2) + return Error("Bad GLOBALVAR_VAR record"); + ProcessingGlobal = true; + VarAlignment = (1 << Record[0]) >> 1; + VarIsConstant = Record[1] != 0; + // Assume (by default) there is a single initializer. + VarInitializersNeeded = 1; + break; + case naclbitc::GLOBALVAR_COMPOUND: + // Global variable has multiple initializers. Changes the + // default number of initializers to the given value in + // Record[0]. + if (!ProcessingGlobal || !VarInit.empty() || + VarInitializersNeeded != 1 || Record.size() != 1) + return Error("Bad GLOBALVAR_COMPOUND record"); + VarInitializersNeeded = Record[0]; + break; + case naclbitc::GLOBALVAR_ZEROFILL: { + // Define an initializer that defines a sequence of zero-filled bytes. + if (!ProcessingGlobal || Record.size() != 1) + return Error("Bad GLOBALVAR_ZEROFILL record"); + Type *Ty = ArrayType::get(Type::getInt8Ty(Context), Record[0]); + Constant *Zero = ConstantAggregateZero::get(Ty); + VarInit.push_back(Zero); + break; + } + case naclbitc::GLOBALVAR_DATA: { + // Defines an initializer defined by a sequence of byte values. + if (!ProcessingGlobal || Record.size() < 1) + return Error("Bad GLOBALVAR_DATA record"); + unsigned Size = Record.size(); + uint8_t *Buf = new uint8_t[Size]; + assert(Buf); + for (unsigned i = 0; i < Size; ++i) + Buf[i] = Record[i]; + Constant *Init = ConstantDataArray::get( + Context, ArrayRef<uint8_t>(Buf, Buf + Size)); + VarInit.push_back(Init); + delete[] Buf; + break; + } + case naclbitc::GLOBALVAR_RELOC: { + // Define a relocation initializer. + if (!ProcessingGlobal || Record.size() < 1 || Record.size() > 2) + return Error("Bad GLOBALVAR_RELOC record"); + Constant *BaseVal = + ValueList.getOrCreateGlobalVarRef(Record[0], TheModule); + if (BaseVal == 0) + return Error("Bad base value in GLOBALVAR_RELOC record"); + Type *IntPtrType = IntegerType::get(Context, 32); + Constant *Val = ConstantExpr::getPtrToInt(BaseVal, IntPtrType); + if (Record.size() == 2) { + uint32_t Addend = Record[1]; + Val = ConstantExpr::getAdd(Val, ConstantInt::get(IntPtrType, + Addend)); + } + VarInit.push_back(Val); + break; + } + case naclbitc::GLOBALVAR_COUNT: + if (Record.size() != 1 || NumGlobals != 0) + return Error("Invalid global count record"); + NumGlobals = Record[0]; + break; + } + + // If more initializers needed for global variable, continue processing. + if (!ProcessingGlobal || VarInit.size() < VarInitializersNeeded) + continue; + + Constant *Init = 0; + switch (VarInit.size()) { + case 0: + return Error("No initializer for global variable in global vars block"); + case 1: + Init = VarInit[0]; + break; + default: + Init = ConstantStruct::getAnon(Context, VarInit, true); + break; + } + GlobalVariable *GV = new GlobalVariable( + *TheModule, Init->getType(), VarIsConstant, + GlobalValue::InternalLinkage, Init, ""); + GV->setAlignment(VarAlignment); + ValueList.AssignGlobalVar(GV, NextValueNo); + ++NextValueNo; + ProcessingGlobal = false; + VarAlignment = 0; + VarIsConstant = false; + VarInitializersNeeded = 0; + VarInit.clear(); + } +} + bool NaClBitcodeReader::ParseValueSymbolTable() { DEBUG(dbgs() << "-> ParseValueSymbolTable\n"); if (Stream.EnterSubBlock(naclbitc::VALUE_SYMTAB_BLOCK_ID)) @@ -691,29 +868,12 @@ bool NaClBitcodeReader::ParseValueSymbolTable() { } } -/// ResolveGlobalAndAliasInits - Resolve all of the initializers for global -/// values and aliases that we can. -bool NaClBitcodeReader::ResolveGlobalAndAliasInits() { - std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInitWorklist; +/// ResolveAliasInits - Resolve all of the initializers for aliases that we can. +bool NaClBitcodeReader::ResolveAliasInits() { std::vector<std::pair<GlobalAlias*, unsigned> > AliasInitWorklist; - GlobalInitWorklist.swap(GlobalInits); AliasInitWorklist.swap(AliasInits); - while (!GlobalInitWorklist.empty()) { - unsigned ValID = GlobalInitWorklist.back().second; - if (ValID >= ValueList.size()) { - // Not ready to resolve this yet, it requires something later in the file. - GlobalInits.push_back(GlobalInitWorklist.back()); - } else { - if (Constant *C = dyn_cast<Constant>(ValueList[ValID])) - GlobalInitWorklist.back().first->setInitializer(C); - else - return Error("Global variable initializer is not a constant!"); - } - GlobalInitWorklist.pop_back(); - } - while (!AliasInitWorklist.empty()) { unsigned ValID = AliasInitWorklist.back().second; if (ValID >= ValueList.size()) { @@ -1199,9 +1359,10 @@ bool NaClBitcodeReader::RememberAndSkipFunctionBody() { bool NaClBitcodeReader::GlobalCleanup() { // Patch the initializers for globals and aliases up. - ResolveGlobalAndAliasInits(); - if (!GlobalInits.empty() || !AliasInits.empty()) - return Error("Malformed global initializer set"); + ResolveAliasInits(); + + if (!AliasInits.empty()) + return Error("Malformed Alias Initializer"); // Look for intrinsic functions which need to be upgraded at some point for (Module::iterator FI = TheModule->begin(), FE = TheModule->end(); @@ -1216,9 +1377,6 @@ bool NaClBitcodeReader::GlobalCleanup() { GI = TheModule->global_begin(), GE = TheModule->global_end(); GI != GE; ++GI) UpgradeGlobalVariable(GI); - // Force deallocation of memory for these vectors to favor the client that - // want lazy deserialization. - std::vector<std::pair<GlobalVariable*, unsigned> >().swap(GlobalInits); std::vector<std::pair<GlobalAlias*, unsigned> >().swap(AliasInits); return false; } @@ -1261,13 +1419,17 @@ bool NaClBitcodeReader::ParseModule(bool Resume) { if (ParseTypeTable()) return true; break; + case naclbitc::GLOBALVAR_BLOCK_ID: + if (ParseGlobalVars()) + return true; + break; case naclbitc::VALUE_SYMTAB_BLOCK_ID: if (ParseValueSymbolTable()) return true; SeenValueSymbolTable = true; break; case naclbitc::CONSTANTS_BLOCK_ID: - if (ParseConstants() || ResolveGlobalAndAliasInits()) + if (ParseConstants() || ResolveAliasInits()) return true; break; case naclbitc::FUNCTION_BLOCK_ID: @@ -1359,57 +1521,8 @@ bool NaClBitcodeReader::ParseModule(bool Resume) { // GLOBALVAR: [pointer type, isconst, initid, // linkage, alignment, section, visibility, threadlocal, // unnamed_addr] - case naclbitc::MODULE_CODE_GLOBALVAR: { - if (Record.size() < 6) - return Error("Invalid MODULE_CODE_GLOBALVAR record"); - Type *Ty = getTypeByID(Record[0]); - if (!Ty) return Error("Invalid MODULE_CODE_GLOBALVAR record"); - if (!Ty->isPointerTy()) - return Error("Global not a pointer type!"); - unsigned AddressSpace = cast<PointerType>(Ty)->getAddressSpace(); - Ty = cast<PointerType>(Ty)->getElementType(); - - bool isConstant = Record[1]; - GlobalValue::LinkageTypes Linkage = GetDecodedLinkage(Record[3]); - unsigned Alignment = (1 << Record[4]) >> 1; - std::string Section; - if (Record[5]) { - if (Record[5]-1 >= SectionTable.size()) - return Error("Invalid section ID"); - Section = SectionTable[Record[5]-1]; - } - GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility; - if (Record.size() > 6) - Visibility = GetDecodedVisibility(Record[6]); - - GlobalVariable::ThreadLocalMode TLM = GlobalVariable::NotThreadLocal; - if (Record.size() > 7) - TLM = GetDecodedThreadLocalMode(Record[7]); - - bool UnnamedAddr = false; - if (Record.size() > 8) - UnnamedAddr = Record[8]; - - bool ExternallyInitialized = false; - if (Record.size() > 9) - ExternallyInitialized = Record[9]; - - GlobalVariable *NewGV = - new GlobalVariable(*TheModule, Ty, isConstant, Linkage, 0, "", 0, - TLM, AddressSpace, ExternallyInitialized); - NewGV->setAlignment(Alignment); - if (!Section.empty()) - NewGV->setSection(Section); - NewGV->setVisibility(Visibility); - NewGV->setUnnamedAddr(UnnamedAddr); - - ValueList.push_back(NewGV); - - // Remember which value to use for the global initializer. - if (unsigned InitID = Record[2]) - GlobalInits.push_back(std::make_pair(NewGV, InitID-1)); - break; - } + case naclbitc::MODULE_CODE_GLOBALVAR: + return Error("Invalid MODULE_CODE_GLOBALVAR record"); // FUNCTION: [type, callingconv, isproto, linkage] case naclbitc::MODULE_CODE_FUNCTION: { if (Record.size() < 4) diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h index 9320de92ea..454875796a 100644 --- a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h +++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h @@ -82,13 +82,32 @@ public: // already been declared. bool createValueFwdRef(unsigned Idx, Type *Ty); + // Declares the type of the forward-referenced constant Idx. Returns + // 0 if an error occurred. + // TODO(kschimpf) Convert these to be like createValueFwdRef and + // getValueFwdRef. Constant *getConstantFwdRef(unsigned Idx, Type *Ty); // Gets the forward reference value for Idx. Value *getValueFwdRef(unsigned Idx); + // Gets the corresponding constant defining the address of the + // corresponding global variable defined by Idx, if already defined. + // Otherwise, creates a forward reference for Idx, and returns the + // placeholder constant for the address of the corresponding global + // variable defined by Idx. + Constant *getOrCreateGlobalVarRef(unsigned Idx, Module* M); + + // Assigns Idx to the given value (if new), or assigns V to Idx (if Idx + // was forward referenced). void AssignValue(Value *V, unsigned Idx); + // Assigns Idx to the given global variable. If the Idx currently has + // a forward reference (built by createGlobalVarFwdRef(unsigned Idx)), + // replaces uses of the global variable forward reference with the + // value GV. + void AssignGlobalVar(GlobalVariable *GV, unsigned Idx); + /// ResolveConstantForwardRefs - Once all constants are read, this method bulk /// resolves any forward references. void ResolveConstantForwardRefs(); @@ -114,7 +133,6 @@ class NaClBitcodeReader : public GVMaterializer { SmallVector<Instruction *, 64> InstructionList; SmallVector<SmallVector<uint64_t, 64>, 64> UseListRecords; - std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInits; std::vector<std::pair<GlobalAlias*, unsigned> > AliasInits; /// FunctionBBs - While parsing a function body, this is a list of the basic @@ -259,13 +277,13 @@ private: bool ParseModule(bool Resume); bool ParseTypeTable(); bool ParseTypeTableBody(); - + bool ParseGlobalVars(); bool ParseValueSymbolTable(); bool ParseConstants(); bool RememberAndSkipFunctionBody(); bool ParseFunctionBody(Function *F); bool GlobalCleanup(); - bool ResolveGlobalAndAliasInits(); + bool ResolveAliasInits(); bool ParseUseLists(); bool InitStream(); bool InitStreamFromBuffer(); diff --git a/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp b/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp index be75af1e40..44aaeb3f0e 100644 --- a/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp +++ b/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp @@ -69,6 +69,15 @@ enum { CST_CONSTANTS_CSTRING_6_ABBREV, CST_CONSTANTS_MAX_ABBREV = CST_CONSTANTS_CSTRING_6_ABBREV, + // GLOBALVAR BLOCK abbrev id's. + GLOBALVAR_VAR_ABBREV = naclbitc::FIRST_APPLICATION_ABBREV, + GLOBALVAR_COMPOUND_ABBREV, + GLOBALVAR_ZEROFILL_ABBREV, + GLOBALVAR_DATA_ABBREV, + GLOBALVAR_RELOC_ABBREV, + GLOBALVAR_RELOC_WITH_ADDEND_ABBREV, + GLOBALVAR_MAX_ABBREV = GLOBALVAR_RELOC_WITH_ADDEND_ABBREV, + // FUNCTION_BLOCK abbrev id's. FUNCTION_INST_LOAD_ABBREV = naclbitc::FIRST_APPLICATION_ABBREV, FUNCTION_INST_BINOP_ABBREV, @@ -89,10 +98,6 @@ enum { TYPE_ARRAY_ABBREV, TYPE_MAX_ABBREV = TYPE_ARRAY_ABBREV, - // MODULE_BLOCK abbrev id's. - MODULE_GLOBALVAR_ABBREV = naclbitc::FIRST_APPLICATION_ABBREV, - MODULE_MAX_ABBREV = MODULE_GLOBALVAR_ABBREV, - // SwitchInst Magic SWITCH_INST_MAGIC = 0x4B5 // May 2012 => 1205 => Hex }; @@ -409,15 +414,124 @@ static unsigned getEncodedVisibility(const GlobalValue *GV) { llvm_unreachable("Invalid visibility"); } -static unsigned getEncodedThreadLocalMode(const GlobalVariable *GV) { - switch (GV->getThreadLocalMode()) { - case GlobalVariable::NotThreadLocal: return 0; - case GlobalVariable::GeneralDynamicTLSModel: return 1; - case GlobalVariable::LocalDynamicTLSModel: return 2; - case GlobalVariable::InitialExecTLSModel: return 3; - case GlobalVariable::LocalExecTLSModel: return 4; +/// \brief Function to convert constant initializers for global +/// variables into corresponding bitcode. Takes advantage that these +/// global variable initializations are normalized (see +/// lib/Transforms/NaCl/FlattenGlobals.cpp). +void WriteGlobalInit(const Constant *C, unsigned GlobalVarID, + SmallVectorImpl<uint32_t> &Vals, + const NaClValueEnumerator &VE, + NaClBitstreamWriter &Stream) { + if (ArrayType *Ty = dyn_cast<ArrayType>(C->getType())) { + if (!Ty->getElementType()->isIntegerTy(8)) + report_fatal_error("Global array initializer not i8"); + uint32_t Size = Ty->getNumElements(); + if (isa<ConstantAggregateZero>(C)) { + Vals.push_back(Size); + Stream.EmitRecord(naclbitc::GLOBALVAR_ZEROFILL, Vals, + GLOBALVAR_ZEROFILL_ABBREV); + Vals.clear(); + } else { + const ConstantDataSequential *CD = cast<ConstantDataSequential>(C); + StringRef Data = CD->getRawDataValues(); + for (size_t i = 0; i < Size; ++i) { + Vals.push_back(Data[i] & 0xFF); + } + Stream.EmitRecord(naclbitc::GLOBALVAR_DATA, Vals, + GLOBALVAR_DATA_ABBREV); + Vals.clear(); + } + return; + } + if (C->getType()->isIntegerTy(32)) { + // This constant defines a relocation. Start by verifying the + // relocation is of the right form. + const ConstantExpr *CE = dyn_cast<ConstantExpr>(C); + if (CE == 0) + report_fatal_error("Global i32 initializer not constant"); + assert(CE); + int32_t Addend = 0; + if (CE->getOpcode() == Instruction::Add) { + const ConstantInt *AddendConst = dyn_cast<ConstantInt>(CE->getOperand(1)); + if (AddendConst == 0) + report_fatal_error("Malformed addend in global relocation initializer"); + Addend = AddendConst->getSExtValue(); + CE = dyn_cast<ConstantExpr>(CE->getOperand(0)); + if (CE == 0) + report_fatal_error( + "Base of global relocation initializer not constant"); + } + if (CE->getOpcode() != Instruction::PtrToInt) + report_fatal_error("Global relocation base doesn't contain ptrtoint"); + GlobalValue *GV = dyn_cast<GlobalValue>(CE->getOperand(0)); + if (GV == 0) + report_fatal_error( + "Argument of ptrtoint in global relocation no global value"); + + // Now generate the corresponding relocation record. + unsigned RelocID = VE.getValueID(GV); + // This is a value index. + unsigned AbbrevToUse = GLOBALVAR_RELOC_ABBREV; + Vals.push_back(RelocID); + if (Addend) { + Vals.push_back(Addend); + AbbrevToUse = GLOBALVAR_RELOC_WITH_ADDEND_ABBREV; + } + Stream.EmitRecord(naclbitc::GLOBALVAR_RELOC, Vals, AbbrevToUse); + Vals.clear(); + return; + } + report_fatal_error("Global initializer is not a SimpleElement"); +} + +// Emit global variables. +static void WriteGlobalVars(const Module *M, + const NaClValueEnumerator &VE, + NaClBitstreamWriter &Stream) { + Stream.EnterSubblock(naclbitc::GLOBALVAR_BLOCK_ID); + SmallVector<uint32_t, 32> Vals; + unsigned GlobalVarID = VE.getFirstGlobalVarID(); + + // Emit the number of global variables. + + Vals.push_back(M->getGlobalList().size()); + Stream.EmitRecord(naclbitc::GLOBALVAR_COUNT, Vals); + Vals.clear(); + + // Now emit each global variable. + for (Module::const_global_iterator + GV = M->global_begin(), E = M->global_end(); + GV != E; ++GV, ++GlobalVarID) { + // Define the global variable. + Vals.push_back(Log2_32(GV->getAlignment()) + 1); + Vals.push_back(GV->isConstant()); + Stream.EmitRecord(naclbitc::GLOBALVAR_VAR, Vals, GLOBALVAR_VAR_ABBREV); + Vals.clear(); + + // Add the field(s). + const Constant *C = GV->getInitializer(); + if (C == 0) + report_fatal_error("Global variable initializer not a constant"); + if (const ConstantStruct *CS = dyn_cast<ConstantStruct>(C)) { + if (!CS->getType()->isPacked()) + report_fatal_error("Global variable type not packed"); + if (CS->getType()->hasName()) + report_fatal_error("Global variable type is named"); + Vals.push_back(CS->getNumOperands()); + Stream.EmitRecord(naclbitc::GLOBALVAR_COMPOUND, Vals, + GLOBALVAR_COMPOUND_ABBREV); + Vals.clear(); + for (unsigned I = 0; I < CS->getNumOperands(); ++I) { + WriteGlobalInit(dyn_cast<Constant>(CS->getOperand(I)), GlobalVarID, + Vals, VE, Stream); + } + } else { + WriteGlobalInit(C, GlobalVarID, Vals, VE, Stream); + } } - llvm_unreachable("Invalid TLS model"); + + assert(GlobalVarID == VE.getFirstGlobalVarID() + VE.getNumGlobalVarIDs()); + Stream.ExitBlock(); } // Emit top-level description of module, including inline asm, @@ -472,65 +586,10 @@ static void WriteModuleInfo(const Module *M, const NaClValueEnumerator &VE, } } - // Emit abbrev for globals, now that we know # sections and max alignment. - // Add an abbrev for common globals with no visibility or thread localness. - // Don't bother emitting vis + thread local abbreviation. - { - NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev(); - Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::MODULE_CODE_GLOBALVAR)); - Abbv->Add(NaClBitCodeAbbrevOp( - NaClBitCodeAbbrevOp::Fixed, NaClBitsNeededForValue(MaxGlobalType))); - Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, 1)); // Constant. - Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 6)); // Initializer. - Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, 4)); // Linkage. - if (MaxAlignment == 0) // Alignment. - Abbv->Add(NaClBitCodeAbbrevOp(0)); - else { - unsigned MaxEncAlignment = Log2_32(MaxAlignment)+1; - Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, - NaClBitsNeededForValue(MaxEncAlignment))); - } - if (SectionMap.empty()) // Section. - Abbv->Add(NaClBitCodeAbbrevOp(0)); - else - Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, - NaClBitsNeededForValue(SectionMap.size()))); - if (MODULE_GLOBALVAR_ABBREV != Stream.EmitAbbrev(Abbv)) - llvm_unreachable("Unexpected abbrev ordering!"); - } - - // Emit the global variable information. + // Emit the function proto information. Note: We do this before + // global variables, so that global variable initializations can + // refer to the functions without a forward reference. SmallVector<unsigned, 64> Vals; - for (Module::const_global_iterator GV = M->global_begin(),E = M->global_end(); - GV != E; ++GV) { - unsigned AbbrevToUse = 0; - - // GLOBALVAR: [type, isconst, initid, - // linkage, alignment, section, visibility, threadlocal, - // unnamed_addr] - Vals.push_back(VE.getTypeID(GV->getType())); - Vals.push_back(GV->isConstant()); - Vals.push_back(GV->isDeclaration() ? 0 : - (VE.getValueID(GV->getInitializer()) + 1)); - Vals.push_back(getEncodedLinkage(GV)); - Vals.push_back(Log2_32(GV->getAlignment())+1); - Vals.push_back(GV->hasSection() ? SectionMap[GV->getSection()] : 0); - if (GV->isThreadLocal() || - GV->getVisibility() != GlobalValue::DefaultVisibility || - GV->hasUnnamedAddr() || GV->isExternallyInitialized()) { - Vals.push_back(getEncodedVisibility(GV)); - Vals.push_back(getEncodedThreadLocalMode(GV)); - Vals.push_back(GV->hasUnnamedAddr()); - Vals.push_back(GV->isExternallyInitialized()); - } else { - AbbrevToUse = MODULE_GLOBALVAR_ABBREV; - } - - Stream.EmitRecord(naclbitc::MODULE_CODE_GLOBALVAR, Vals, AbbrevToUse); - Vals.clear(); - } - - // Emit the function proto information. for (Module::const_iterator F = M->begin(), E = M->end(); F != E; ++F) { // FUNCTION: [type, callingconv, isproto, linkage] Vals.push_back(VE.getTypeID(F->getType())); @@ -543,6 +602,9 @@ static void WriteModuleInfo(const Module *M, const NaClValueEnumerator &VE, Vals.clear(); } + // Emit the global variable information. + WriteGlobalVars(M, VE, Stream); + // Emit the alias information. for (Module::const_alias_iterator AI = M->alias_begin(), E = M->alias_end(); AI != E; ++AI) { @@ -1561,13 +1623,66 @@ static void WriteBlockInfo(const NaClValueEnumerator &VE, llvm_unreachable("Unexpected abbrev ordering!"); } + { // VAR abbrev for GLOBALVAR_BLOCK. + NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev(); + Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::GLOBALVAR_VAR)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 6)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, 1)); + if (Stream.EmitBlockInfoAbbrev(naclbitc::GLOBALVAR_BLOCK_ID, + Abbv) != GLOBALVAR_VAR_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // COMPOUND abbrev for GLOBALVAR_BLOCK. + NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev(); + Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::GLOBALVAR_COMPOUND)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 8)); + if (Stream.EmitBlockInfoAbbrev(naclbitc::GLOBALVAR_BLOCK_ID, + Abbv) != GLOBALVAR_COMPOUND_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // ZEROFILL abbrev for GLOBALVAR_BLOCK. + NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev(); + Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::GLOBALVAR_ZEROFILL)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 8)); + if (Stream.EmitBlockInfoAbbrev(naclbitc::GLOBALVAR_BLOCK_ID, + Abbv) != GLOBALVAR_ZEROFILL_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // DATA abbrev for GLOBALVAR_BLOCK. + NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev(); + Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::GLOBALVAR_DATA)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, 8)); + if (Stream.EmitBlockInfoAbbrev(naclbitc::GLOBALVAR_BLOCK_ID, + Abbv) != GLOBALVAR_DATA_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // RELOC abbrev for GLOBALVAR_BLOCK. + NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev(); + Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::GLOBALVAR_RELOC)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 6)); + if (Stream.EmitBlockInfoAbbrev(naclbitc::GLOBALVAR_BLOCK_ID, + Abbv) != GLOBALVAR_RELOC_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // RELOC_WITH_ADDEND_ABBREV abbrev for GLOBALVAR_BLOCK. + NaClBitCodeAbbrev *Abbv = new NaClBitCodeAbbrev(); + Abbv->Add(NaClBitCodeAbbrevOp(naclbitc::GLOBALVAR_RELOC)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 6)); + Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 6)); + if (Stream.EmitBlockInfoAbbrev( + naclbitc::GLOBALVAR_BLOCK_ID, + Abbv) != GLOBALVAR_RELOC_WITH_ADDEND_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + Stream.ExitBlock(); } /// WriteModule - Emit the specified module to the bitstream. static void WriteModule(const Module *M, NaClBitstreamWriter &Stream) { DEBUG(dbgs() << "-> WriteModule\n"); - Stream.EnterSubblock(naclbitc::MODULE_BLOCK_ID, MODULE_MAX_ABBREV); + Stream.EnterSubblock(naclbitc::MODULE_BLOCK_ID); SmallVector<unsigned, 1> Vals; unsigned CurVersion = 1; diff --git a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp index feb14cdb0c..393c5bc934 100644 --- a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp +++ b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp @@ -42,16 +42,21 @@ NaClValueEnumerator::NaClValueEnumerator(const Module *M) { // constructor completes. TypeCountMapType count_map; TypeCountMap = &count_map; - // Enumerate the global variables. - for (Module::const_global_iterator I = M->global_begin(), - E = M->global_end(); I != E; ++I) - EnumerateValue(I); - // Enumerate the functions. + // Enumerate the functions. Note: We do this before global + // variables, so that global variable initializations can refer to + // the functions without a forward reference. for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I) { EnumerateValue(I); } + // Enumerate the global variables. + FirstGlobalVarID = Values.size(); + for (Module::const_global_iterator I = M->global_begin(), + E = M->global_end(); I != E; ++I) + EnumerateValue(I); + NumGlobalVarIDs = Values.size() - FirstGlobalVarID; + // Enumerate the aliases. for (Module::const_alias_iterator I = M->alias_begin(), E = M->alias_end(); I != E; ++I) @@ -60,11 +65,8 @@ NaClValueEnumerator::NaClValueEnumerator(const Module *M) { // Remember what is the cutoff between globalvalue's and other constants. unsigned FirstConstant = Values.size(); - // Enumerate the global variable initializers. - for (Module::const_global_iterator I = M->global_begin(), - E = M->global_end(); I != E; ++I) - if (I->hasInitializer()) - EnumerateValue(I->getInitializer()); + // Skip global variable initializers since they are handled within + // WriteGlobalVars of file NaClBitcodeWriter.cpp. // Enumerate the aliasees. for (Module::const_alias_iterator I = M->alias_begin(), E = M->alias_end(); diff --git a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h index 90946551f5..e98a091ba8 100644 --- a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h +++ b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h @@ -79,6 +79,11 @@ private: /// than necessary. SmallSet<unsigned, 32> FnForwardTypeRefs; + // The index of the first global variable ID in the bitcode file. + unsigned FirstGlobalVarID; + // The number of global variable IDs defined in the bitcode file. + unsigned NumGlobalVarIDs; + NaClValueEnumerator(const NaClValueEnumerator &) LLVM_DELETED_FUNCTION; void operator=(const NaClValueEnumerator &) LLVM_DELETED_FUNCTION; public: @@ -87,6 +92,14 @@ public: void dump() const; void print(raw_ostream &OS, const ValueMapType &Map, const char *Name) const; + unsigned getFirstGlobalVarID() const { + return FirstGlobalVarID; + } + + unsigned getNumGlobalVarIDs() const { + return NumGlobalVarIDs; + } + unsigned getValueID(const Value *V) const; unsigned getTypeID(Type *T) const { diff --git a/test/NaCl/Bitcode/globalvars.ll b/test/NaCl/Bitcode/globalvars.ll new file mode 100644 index 0000000000..c6e6f2f17a --- /dev/null +++ b/test/NaCl/Bitcode/globalvars.ll @@ -0,0 +1,98 @@ +; RUN: llvm-as < %s | pnacl-freeze | pnacl-thaw | llvm-dis - | FileCheck %s +; RUN: llvm-as < %s | pnacl-freeze | pnacl-bcanalyzer -dump \ +; RUN: | FileCheck %s -check-prefix=BC + +; Test that we generate appropriate bitcode values for global variables. + +; Make sure that the function declaration for function func (below) +; appears before the global variables block. +; BC: <FUNCTION op0=5 op1=0 op2=0 op3=0/> + +; Make sure we begin the globals block after function declarations. +; BC-NEXT: <GLOBALVAR_BLOCK +; BC-NEXT: <COUNT op0=15/> + +@bytes = internal global [7 x i8] c"abcdefg" +; CHECK: @bytes = internal global [7 x i8] c"abcdefg" +; BC-NEXT: <VAR abbrevid=4 op0=0 op1=0/> +; BC-NEXT: <DATA abbrevid=7 op0=97 op1=98 op2=99 op3=100 op4=101 op5=102 op6=103/> + + +@ptr_to_ptr = internal global i32 ptrtoint (i32* @ptr to i32) +; CHECK: @ptr_to_ptr = internal global i32 ptrtoint (i32* @ptr to i32) +; BC-NEXT: <VAR abbrevid=4 op0=0 op1=0/> +; BC-NEXT: <RELOC abbrevid=8 op0=5/> + +@ptr_to_func = internal global i32 ptrtoint (void ()* @func to i32) +; CHECK: @ptr_to_func = internal global i32 ptrtoint (void ()* @func to i32) +; BC-NEXT: <VAR abbrevid=4 op0=0 op1=0/> +; BC-NEXT: <RELOC abbrevid=8 op0=0/> + +@compound = internal global <{ [3 x i8], i32 }> <{ [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) }> +; CHECK: @compound = internal global <{ [3 x i8], i32 }> <{ [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) }> +; BC-NEXT: <VAR abbrevid=4 op0=0 op1=0/> +; BC-NEXT: <COMPOUND abbrevid=5 op0=2/> +; BC-NEXT: <DATA abbrevid=7 op0=102 op1=111 op2=111/> +; BC-NEXT: <RELOC abbrevid=8 op0=0/> + +@ptr = internal global i32 ptrtoint ([7 x i8]* @bytes to i32) +; CHECK: @ptr = internal global i32 ptrtoint ([7 x i8]* @bytes to i32) +; BC-NEXT: <VAR abbrevid=4 op0=0 op1=0/> +; BC-NEXT: <RELOC abbrevid=8 op0=1/> + +@addend_ptr = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 1) +; CHECK: @addend_ptr = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 1) +; BC-NEXT: <VAR abbrevid=4 op0=0 op1=0/> +; BC-NEXT: <RELOC abbrevid=9 op0=5 op1=1/> + +@addend_negative = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 -1) +; CHECK: @addend_negative = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 -1) +; BC-NEXT: <VAR abbrevid=4 op0=0 op1=0/> +; BC-NEXT: <RELOC abbrevid=9 op0=5 op1=4294967295/> + +@addend_array1 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 1) +; CHECK: @addend_array1 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 1) +; BC-NEXT: <VAR abbrevid=4 op0=0 op1=0/> +; BC-NEXT: <RELOC abbrevid=9 op0=1 op1=1/> + +@addend_array2 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 7) +; CHECK: @addend_array2 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 7) +; BC-NEXT: <VAR abbrevid=4 op0=0 op1=0/> +; BC-NEXT: <RELOC abbrevid=9 op0=1 op1=7/> + +@addend_array3 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 9) +; CHECK: @addend_array3 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 9) +; BC-NEXT: <VAR abbrevid=4 op0=0 op1=0/> +; BC-NEXT: <RELOC abbrevid=9 op0=1 op1=9/> + +@addend_struct1 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 1) +; CHECK: @addend_struct1 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 1) +; BC-NEXT: <VAR abbrevid=4 op0=0 op1=0/> +; BC-NEXT: <RELOC abbrevid=9 op0=4 op1=1/> + +@addend_struct2 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 4) +; CHECK: @addend_struct2 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 4) +; BC-NEXT: <VAR abbrevid=4 op0=0 op1=0/> +; BC-NEXT: <RELOC abbrevid=9 op0=4 op1=4/> + +@ptr_to_func_align = internal global i32 ptrtoint (void ()* @func to i32), align 8 +; CHECK: @ptr_to_func_align = internal global i32 ptrtoint (void ()* @func to i32), align 8 +; BC-NEXT: <VAR abbrevid=4 op0=4 op1=0/> +; BC-NEXT: <RELOC abbrevid=8 op0=0/> + +@char = internal constant [1 x i8] c"0" +; CHECK: @char = internal constant [1 x i8] c"0" +; BC-NEXT: <VAR abbrevid=4 op0=0 op1=1/> +; BC-NEXT: <DATA abbrevid=7 op0=48/> + +@short = internal constant [2 x i8] zeroinitializer +; CHECK: @short = internal constant [2 x i8] zeroinitializer +; BC-NEXT: <VAR abbrevid=4 op0=0 op1=1/> +; BC-NEXT: <ZEROFILL abbrevid=6 op0=2/> + +; BC-NEXT: </GLOBALVAR_BLOCK> + +define void @func() { + ret void +} + diff --git a/tools/pnacl-bcanalyzer/pnacl-bcanalyzer.cpp b/tools/pnacl-bcanalyzer/pnacl-bcanalyzer.cpp index ee002dd729..7a44542022 100644 --- a/tools/pnacl-bcanalyzer/pnacl-bcanalyzer.cpp +++ b/tools/pnacl-bcanalyzer/pnacl-bcanalyzer.cpp @@ -97,6 +97,7 @@ static const char *GetBlockName(unsigned BlockID, case naclbitc::METADATA_BLOCK_ID: return "METADATA_BLOCK"; case naclbitc::METADATA_ATTACHMENT_ID: return "METADATA_ATTACHMENT_BLOCK"; case naclbitc::USELIST_BLOCK_ID: return "USELIST_BLOCK_ID"; + case naclbitc::GLOBALVAR_BLOCK_ID: return "GLOBALVAR_BLOCK"; } } @@ -259,6 +260,16 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, default:return 0; case naclbitc::USELIST_CODE_ENTRY: return "USELIST_CODE_ENTRY"; } + case naclbitc::GLOBALVAR_BLOCK_ID: + switch (CodeID) { + default: return 0; + case naclbitc::GLOBALVAR_VAR: return "VAR"; + case naclbitc::GLOBALVAR_COMPOUND: return "COMPOUND"; + case naclbitc::GLOBALVAR_ZEROFILL: return "ZEROFILL"; + case naclbitc::GLOBALVAR_DATA: return "DATA"; + case naclbitc::GLOBALVAR_RELOC: return "RELOC"; + case naclbitc::GLOBALVAR_COUNT: return "COUNT"; + } } } |