1 //===- COFFObjectFile.cpp - COFF object file implementation -----*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file declares the COFFObjectFile class. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/Object/COFF.h" 15 #include "llvm/ADT/StringSwitch.h" 16 #include "llvm/ADT/Triple.h" 17 18 using namespace llvm; 19 using namespace object; 20 21 namespace { 22 using support::ulittle8_t; 23 using support::ulittle16_t; 24 using support::ulittle32_t; 25 using support::little16_t; 26 } 27 28 SymbolRef COFFObjectFile::getSymbolNext(DataRefImpl Symb) const { 29 const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 30 symb += 1 + symb->NumberOfAuxSymbols; 31 Symb.p = reinterpret_cast<intptr_t>(symb); 32 return SymbolRef(Symb, this); 33 } 34 35 StringRef COFFObjectFile::getSymbolName(DataRefImpl Symb) const { 36 const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 37 // Check for string table entry. First 4 bytes are 0. 38 if (symb->Name.Offset.Zeroes == 0) { 39 uint32_t Offset = symb->Name.Offset.Offset; 40 return StringRef(getString(Offset)); 41 } 42 43 if (symb->Name.ShortName[7] == 0) 44 // Null terminated, let ::strlen figure out the length. 45 return StringRef(symb->Name.ShortName); 46 // Not null terminated, use all 8 bytes. 47 return StringRef(symb->Name.ShortName, 8); 48 } 49 50 uint64_t COFFObjectFile::getSymbolAddress(DataRefImpl Symb) const { 51 const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 52 const coff_section *Section = getSection(symb->SectionNumber); 53 char Type = getSymbolNMTypeChar(Symb); 54 if (Type == 'U' || Type == 'w') 55 return UnknownAddressOrSize; 56 if (Section) 57 return Section->VirtualAddress + symb->Value; 58 return symb->Value; 59 } 60 61 uint64_t COFFObjectFile::getSymbolSize(DataRefImpl Symb) const { 62 // FIXME: Return the correct size. This requires looking at all the symbols 63 // in the same section as this symbol, and looking for either the next 64 // symbol, or the end of the section. 65 const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 66 const coff_section *Section = getSection(symb->SectionNumber); 67 char Type = getSymbolNMTypeChar(Symb); 68 if (Type == 'U' || Type == 'w') 69 return UnknownAddressOrSize; 70 if (Section) 71 return Section->SizeOfRawData - symb->Value; 72 return 0; 73 } 74 75 char COFFObjectFile::getSymbolNMTypeChar(DataRefImpl Symb) const { 76 const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 77 char ret = StringSwitch<char>(getSymbolName(Symb)) 78 .StartsWith(".debug", 'N') 79 .StartsWith(".sxdata", 'N') 80 .Default('?'); 81 82 if (ret != '?') 83 return ret; 84 85 uint32_t Characteristics = 0; 86 if (const coff_section *Section = getSection(symb->SectionNumber)) { 87 Characteristics = Section->Characteristics; 88 } 89 90 switch (symb->SectionNumber) { 91 case COFF::IMAGE_SYM_UNDEFINED: 92 // Check storage classes. 93 if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL) 94 return 'w'; // Don't do ::toupper. 95 else 96 ret = 'u'; 97 break; 98 case COFF::IMAGE_SYM_ABSOLUTE: 99 ret = 'a'; 100 break; 101 case COFF::IMAGE_SYM_DEBUG: 102 ret = 'n'; 103 break; 104 default: 105 // Check section type. 106 if (Characteristics & COFF::IMAGE_SCN_CNT_CODE) 107 ret = 't'; 108 else if ( Characteristics & COFF::IMAGE_SCN_MEM_READ 109 && ~Characteristics & COFF::IMAGE_SCN_MEM_WRITE) // Read only. 110 ret = 'r'; 111 else if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) 112 ret = 'd'; 113 else if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) 114 ret = 'b'; 115 else if (Characteristics & COFF::IMAGE_SCN_LNK_INFO) 116 ret = 'i'; 117 118 // Check for section symbol. 119 else if ( symb->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC 120 && symb->Value == 0) 121 ret = 's'; 122 } 123 124 if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL) 125 ret = ::toupper(ret); 126 127 return ret; 128 } 129 130 bool COFFObjectFile::isSymbolInternal(DataRefImpl Symb) const { 131 return false; 132 } 133 134 SectionRef COFFObjectFile::getSectionNext(DataRefImpl Sec) const { 135 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 136 sec += 1; 137 Sec.p = reinterpret_cast<intptr_t>(sec); 138 return SectionRef(Sec, this); 139 } 140 141 StringRef COFFObjectFile::getSectionName(DataRefImpl Sec) const { 142 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 143 StringRef name; 144 if (sec->Name[7] == 0) 145 // Null terminated, let ::strlen figure out the length. 146 name = sec->Name; 147 else 148 // Not null terminated, use all 8 bytes. 149 name = StringRef(sec->Name, 8); 150 151 // Check for string table entry. First byte is '/'. 152 if (name[0] == '/') { 153 uint32_t Offset; 154 name.substr(1).getAsInteger(10, Offset); 155 return StringRef(getString(Offset)); 156 } 157 158 // It's just a normal name. 159 return name; 160 } 161 162 uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Sec) const { 163 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 164 return sec->VirtualAddress; 165 } 166 167 uint64_t COFFObjectFile::getSectionSize(DataRefImpl Sec) const { 168 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 169 return sec->SizeOfRawData; 170 } 171 172 StringRef COFFObjectFile::getSectionContents(DataRefImpl Sec) const { 173 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 174 return StringRef(reinterpret_cast<const char *>(base() 175 + sec->PointerToRawData), 176 sec->SizeOfRawData); 177 } 178 179 bool COFFObjectFile::isSectionText(DataRefImpl Sec) const { 180 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 181 return sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE; 182 } 183 184 COFFObjectFile::COFFObjectFile(MemoryBuffer *Object, error_code &ec) 185 : ObjectFile(Binary::isCOFF, Object, ec) { 186 187 HeaderOff = 0; 188 189 if (base()[0] == 0x4d && base()[1] == 0x5a) { 190 // PE/COFF, seek through MS-DOS compatibility stub and 4-byte 191 // PE signature to find 'normal' COFF header. 192 HeaderOff += *reinterpret_cast<const ulittle32_t *>(base() + 0x3c); 193 HeaderOff += 4; 194 } 195 196 Header = reinterpret_cast<const coff_file_header *>(base() + HeaderOff); 197 SectionTable = 198 reinterpret_cast<const coff_section *>( base() 199 + HeaderOff 200 + sizeof(coff_file_header) 201 + Header->SizeOfOptionalHeader); 202 SymbolTable = 203 reinterpret_cast<const coff_symbol *>(base() 204 + Header->PointerToSymbolTable); 205 206 // Find string table. 207 StringTable = reinterpret_cast<const char *>(base()) 208 + Header->PointerToSymbolTable 209 + Header->NumberOfSymbols * 18; 210 } 211 212 ObjectFile::symbol_iterator COFFObjectFile::begin_symbols() const { 213 DataRefImpl ret; 214 memset(&ret, 0, sizeof(DataRefImpl)); 215 ret.p = reinterpret_cast<intptr_t>(SymbolTable); 216 return symbol_iterator(SymbolRef(ret, this)); 217 } 218 219 ObjectFile::symbol_iterator COFFObjectFile::end_symbols() const { 220 // The symbol table ends where the string table begins. 221 DataRefImpl ret; 222 memset(&ret, 0, sizeof(DataRefImpl)); 223 ret.p = reinterpret_cast<intptr_t>(StringTable); 224 return symbol_iterator(SymbolRef(ret, this)); 225 } 226 227 ObjectFile::section_iterator COFFObjectFile::begin_sections() const { 228 DataRefImpl ret; 229 memset(&ret, 0, sizeof(DataRefImpl)); 230 ret.p = reinterpret_cast<intptr_t>(SectionTable); 231 return section_iterator(SectionRef(ret, this)); 232 } 233 234 ObjectFile::section_iterator COFFObjectFile::end_sections() const { 235 DataRefImpl ret; 236 memset(&ret, 0, sizeof(DataRefImpl)); 237 ret.p = reinterpret_cast<intptr_t>(SectionTable + Header->NumberOfSections); 238 return section_iterator(SectionRef(ret, this)); 239 } 240 241 uint8_t COFFObjectFile::getBytesInAddress() const { 242 return getArch() == Triple::x86_64 ? 8 : 4; 243 } 244 245 StringRef COFFObjectFile::getFileFormatName() const { 246 switch(Header->Machine) { 247 case COFF::IMAGE_FILE_MACHINE_I386: 248 return "COFF-i386"; 249 case COFF::IMAGE_FILE_MACHINE_AMD64: 250 return "COFF-x86-64"; 251 default: 252 return "COFF-<unknown arch>"; 253 } 254 } 255 256 unsigned COFFObjectFile::getArch() const { 257 switch(Header->Machine) { 258 case COFF::IMAGE_FILE_MACHINE_I386: 259 return Triple::x86; 260 case COFF::IMAGE_FILE_MACHINE_AMD64: 261 return Triple::x86_64; 262 default: 263 return Triple::UnknownArch; 264 } 265 } 266 267 const coff_section *COFFObjectFile::getSection(std::size_t index) const { 268 if (index > 0 && index <= Header->NumberOfSections) 269 return SectionTable + (index - 1); 270 return 0; 271 } 272 273 const char *COFFObjectFile::getString(std::size_t offset) const { 274 const ulittle32_t *StringTableSize = 275 reinterpret_cast<const ulittle32_t *>(StringTable); 276 if (offset < *StringTableSize) 277 return StringTable + offset; 278 return 0; 279 } 280 281 namespace llvm { 282 283 ObjectFile *ObjectFile::createCOFFObjectFile(MemoryBuffer *Object) { 284 error_code ec; 285 return new COFFObjectFile(Object, ec); 286 } 287 288 } // end namespace llvm 289