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/ADT/StringSwitch.h" 15 #include "llvm/ADT/Triple.h" 16 #include "llvm/Object/ObjectFile.h" 17 #include "llvm/Support/COFF.h" 18 #include "llvm/Support/Endian.h" 19 20 using namespace llvm; 21 using namespace object; 22 23 namespace { 24 using support::ulittle8_t; 25 using support::ulittle16_t; 26 using support::ulittle32_t; 27 using support::little16_t; 28 } 29 30 namespace { 31 struct coff_file_header { 32 ulittle16_t Machine; 33 ulittle16_t NumberOfSections; 34 ulittle32_t TimeDateStamp; 35 ulittle32_t PointerToSymbolTable; 36 ulittle32_t NumberOfSymbols; 37 ulittle16_t SizeOfOptionalHeader; 38 ulittle16_t Characteristics; 39 }; 40 } 41 42 extern char coff_file_header_layout_static_assert 43 [sizeof(coff_file_header) == 20 ? 1 : -1]; 44 45 namespace { 46 struct coff_symbol { 47 struct StringTableOffset { 48 ulittle32_t Zeroes; 49 ulittle32_t Offset; 50 }; 51 52 union { 53 char ShortName[8]; 54 StringTableOffset Offset; 55 } Name; 56 57 ulittle32_t Value; 58 little16_t SectionNumber; 59 60 struct { 61 ulittle8_t BaseType; 62 ulittle8_t ComplexType; 63 } Type; 64 65 ulittle8_t StorageClass; 66 ulittle8_t NumberOfAuxSymbols; 67 }; 68 } 69 70 extern char coff_coff_symbol_layout_static_assert 71 [sizeof(coff_symbol) == 18 ? 1 : -1]; 72 73 namespace { 74 struct coff_section { 75 char Name[8]; 76 ulittle32_t VirtualSize; 77 ulittle32_t VirtualAddress; 78 ulittle32_t SizeOfRawData; 79 ulittle32_t PointerToRawData; 80 ulittle32_t PointerToRelocations; 81 ulittle32_t PointerToLinenumbers; 82 ulittle16_t NumberOfRelocations; 83 ulittle16_t NumberOfLinenumbers; 84 ulittle32_t Characteristics; 85 }; 86 } 87 88 extern char coff_coff_section_layout_static_assert 89 [sizeof(coff_section) == 40 ? 1 : -1]; 90 91 namespace { 92 class COFFObjectFile : public ObjectFile { 93 private: 94 uint64_t HeaderOff; 95 const coff_file_header *Header; 96 const coff_section *SectionTable; 97 const coff_symbol *SymbolTable; 98 const char *StringTable; 99 100 const coff_section *getSection(std::size_t index) const; 101 const char *getString(std::size_t offset) const; 102 103 protected: 104 virtual SymbolRef getSymbolNext(DataRefImpl Symb) const; 105 virtual StringRef getSymbolName(DataRefImpl Symb) const; 106 virtual uint64_t getSymbolAddress(DataRefImpl Symb) const; 107 virtual uint64_t getSymbolSize(DataRefImpl Symb) const; 108 virtual char getSymbolNMTypeChar(DataRefImpl Symb) const; 109 virtual bool isSymbolInternal(DataRefImpl Symb) const; 110 111 virtual SectionRef getSectionNext(DataRefImpl Sec) const; 112 virtual StringRef getSectionName(DataRefImpl Sec) const; 113 virtual uint64_t getSectionAddress(DataRefImpl Sec) const; 114 virtual uint64_t getSectionSize(DataRefImpl Sec) const; 115 virtual StringRef getSectionContents(DataRefImpl Sec) const; 116 virtual bool isSectionText(DataRefImpl Sec) const; 117 118 public: 119 COFFObjectFile(MemoryBuffer *Object); 120 virtual symbol_iterator begin_symbols() const; 121 virtual symbol_iterator end_symbols() const; 122 virtual section_iterator begin_sections() const; 123 virtual section_iterator end_sections() const; 124 125 virtual uint8_t getBytesInAddress() const; 126 virtual StringRef getFileFormatName() const; 127 virtual unsigned getArch() const; 128 }; 129 } // end namespace 130 131 SymbolRef COFFObjectFile::getSymbolNext(DataRefImpl Symb) const { 132 const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 133 symb += 1 + symb->NumberOfAuxSymbols; 134 Symb.p = reinterpret_cast<intptr_t>(symb); 135 return SymbolRef(Symb, this); 136 } 137 138 StringRef COFFObjectFile::getSymbolName(DataRefImpl Symb) const { 139 const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 140 // Check for string table entry. First 4 bytes are 0. 141 if (symb->Name.Offset.Zeroes == 0) { 142 uint32_t Offset = symb->Name.Offset.Offset; 143 return StringRef(getString(Offset)); 144 } 145 146 if (symb->Name.ShortName[7] == 0) 147 // Null terminated, let ::strlen figure out the length. 148 return StringRef(symb->Name.ShortName); 149 // Not null terminated, use all 8 bytes. 150 return StringRef(symb->Name.ShortName, 8); 151 } 152 153 uint64_t COFFObjectFile::getSymbolAddress(DataRefImpl Symb) const { 154 const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 155 const coff_section *Section = getSection(symb->SectionNumber); 156 char Type = getSymbolNMTypeChar(Symb); 157 if (Type == 'U' || Type == 'w') 158 return UnknownAddressOrSize; 159 if (Section) 160 return Section->VirtualAddress + symb->Value; 161 return symb->Value; 162 } 163 164 uint64_t COFFObjectFile::getSymbolSize(DataRefImpl Symb) const { 165 // FIXME: Return the correct size. This requires looking at all the symbols 166 // in the same section as this symbol, and looking for either the next 167 // symbol, or the end of the section. 168 const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 169 const coff_section *Section = getSection(symb->SectionNumber); 170 char Type = getSymbolNMTypeChar(Symb); 171 if (Type == 'U' || Type == 'w') 172 return UnknownAddressOrSize; 173 if (Section) 174 return Section->SizeOfRawData - symb->Value; 175 return 0; 176 } 177 178 char COFFObjectFile::getSymbolNMTypeChar(DataRefImpl Symb) const { 179 const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 180 char ret = StringSwitch<char>(getSymbolName(Symb)) 181 .StartsWith(".debug", 'N') 182 .StartsWith(".sxdata", 'N') 183 .Default('?'); 184 185 if (ret != '?') 186 return ret; 187 188 uint32_t Characteristics = 0; 189 if (const coff_section *Section = getSection(symb->SectionNumber)) { 190 Characteristics = Section->Characteristics; 191 } 192 193 switch (symb->SectionNumber) { 194 case COFF::IMAGE_SYM_UNDEFINED: 195 // Check storage classes. 196 if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL) 197 return 'w'; // Don't do ::toupper. 198 else 199 ret = 'u'; 200 break; 201 case COFF::IMAGE_SYM_ABSOLUTE: 202 ret = 'a'; 203 break; 204 case COFF::IMAGE_SYM_DEBUG: 205 ret = 'n'; 206 break; 207 default: 208 // Check section type. 209 if (Characteristics & COFF::IMAGE_SCN_CNT_CODE) 210 ret = 't'; 211 else if ( Characteristics & COFF::IMAGE_SCN_MEM_READ 212 && ~Characteristics & COFF::IMAGE_SCN_MEM_WRITE) // Read only. 213 ret = 'r'; 214 else if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) 215 ret = 'd'; 216 else if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) 217 ret = 'b'; 218 else if (Characteristics & COFF::IMAGE_SCN_LNK_INFO) 219 ret = 'i'; 220 221 // Check for section symbol. 222 else if ( symb->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC 223 && symb->Value == 0) 224 ret = 's'; 225 } 226 227 if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL) 228 ret = ::toupper(ret); 229 230 return ret; 231 } 232 233 bool COFFObjectFile::isSymbolInternal(DataRefImpl Symb) const { 234 return false; 235 } 236 237 SectionRef COFFObjectFile::getSectionNext(DataRefImpl Sec) const { 238 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 239 sec += 1; 240 Sec.p = reinterpret_cast<intptr_t>(sec); 241 return SectionRef(Sec, this); 242 } 243 244 StringRef COFFObjectFile::getSectionName(DataRefImpl Sec) const { 245 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 246 StringRef name; 247 if (sec->Name[7] == 0) 248 // Null terminated, let ::strlen figure out the length. 249 name = sec->Name; 250 else 251 // Not null terminated, use all 8 bytes. 252 name = StringRef(sec->Name, 8); 253 254 // Check for string table entry. First byte is '/'. 255 if (name[0] == '/') { 256 uint32_t Offset; 257 name.substr(1).getAsInteger(10, Offset); 258 return StringRef(getString(Offset)); 259 } 260 261 // It's just a normal name. 262 return name; 263 } 264 265 uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Sec) const { 266 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 267 return sec->VirtualAddress; 268 } 269 270 uint64_t COFFObjectFile::getSectionSize(DataRefImpl Sec) const { 271 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 272 return sec->SizeOfRawData; 273 } 274 275 StringRef COFFObjectFile::getSectionContents(DataRefImpl Sec) const { 276 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 277 return StringRef(reinterpret_cast<const char *>(base + sec->PointerToRawData), 278 sec->SizeOfRawData); 279 } 280 281 bool COFFObjectFile::isSectionText(DataRefImpl Sec) const { 282 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 283 return sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE; 284 } 285 286 COFFObjectFile::COFFObjectFile(MemoryBuffer *Object) 287 : ObjectFile(Object) { 288 289 HeaderOff = 0; 290 291 if (base[0] == 0x4d && base[1] == 0x5a) { 292 // PE/COFF, seek through MS-DOS compatibility stub and 4-byte 293 // PE signature to find 'normal' COFF header. 294 HeaderOff += *reinterpret_cast<const ulittle32_t *>(base + 0x3c); 295 HeaderOff += 4; 296 } 297 298 Header = reinterpret_cast<const coff_file_header *>(base + HeaderOff); 299 SectionTable = 300 reinterpret_cast<const coff_section *>( base 301 + HeaderOff 302 + sizeof(coff_file_header) 303 + Header->SizeOfOptionalHeader); 304 SymbolTable = 305 reinterpret_cast<const coff_symbol *>(base + Header->PointerToSymbolTable); 306 307 // Find string table. 308 StringTable = reinterpret_cast<const char *>(base) 309 + Header->PointerToSymbolTable 310 + Header->NumberOfSymbols * 18; 311 } 312 313 ObjectFile::symbol_iterator COFFObjectFile::begin_symbols() const { 314 DataRefImpl ret; 315 memset(&ret, 0, sizeof(DataRefImpl)); 316 ret.p = reinterpret_cast<intptr_t>(SymbolTable); 317 return symbol_iterator(SymbolRef(ret, this)); 318 } 319 320 ObjectFile::symbol_iterator COFFObjectFile::end_symbols() const { 321 // The symbol table ends where the string table begins. 322 DataRefImpl ret; 323 memset(&ret, 0, sizeof(DataRefImpl)); 324 ret.p = reinterpret_cast<intptr_t>(StringTable); 325 return symbol_iterator(SymbolRef(ret, this)); 326 } 327 328 ObjectFile::section_iterator COFFObjectFile::begin_sections() const { 329 DataRefImpl ret; 330 memset(&ret, 0, sizeof(DataRefImpl)); 331 ret.p = reinterpret_cast<intptr_t>(SectionTable); 332 return section_iterator(SectionRef(ret, this)); 333 } 334 335 ObjectFile::section_iterator COFFObjectFile::end_sections() const { 336 DataRefImpl ret; 337 memset(&ret, 0, sizeof(DataRefImpl)); 338 ret.p = reinterpret_cast<intptr_t>(SectionTable + Header->NumberOfSections); 339 return section_iterator(SectionRef(ret, this)); 340 } 341 342 uint8_t COFFObjectFile::getBytesInAddress() const { 343 return getArch() == Triple::x86_64 ? 8 : 4; 344 } 345 346 StringRef COFFObjectFile::getFileFormatName() const { 347 switch(Header->Machine) { 348 case COFF::IMAGE_FILE_MACHINE_I386: 349 return "COFF-i386"; 350 case COFF::IMAGE_FILE_MACHINE_AMD64: 351 return "COFF-x86-64"; 352 default: 353 return "COFF-<unknown arch>"; 354 } 355 } 356 357 unsigned COFFObjectFile::getArch() const { 358 switch(Header->Machine) { 359 case COFF::IMAGE_FILE_MACHINE_I386: 360 return Triple::x86; 361 case COFF::IMAGE_FILE_MACHINE_AMD64: 362 return Triple::x86_64; 363 default: 364 return Triple::UnknownArch; 365 } 366 } 367 368 const coff_section *COFFObjectFile::getSection(std::size_t index) const { 369 if (index > 0 && index <= Header->NumberOfSections) 370 return SectionTable + (index - 1); 371 return 0; 372 } 373 374 const char *COFFObjectFile::getString(std::size_t offset) const { 375 const ulittle32_t *StringTableSize = 376 reinterpret_cast<const ulittle32_t *>(StringTable); 377 if (offset < *StringTableSize) 378 return StringTable + offset; 379 return 0; 380 } 381 382 namespace llvm { 383 384 ObjectFile *ObjectFile::createCOFFObjectFile(MemoryBuffer *Object) { 385 return new COFFObjectFile(Object); 386 } 387 388 } // end namespace llvm 389