1 //===- ELFObjectFileTest.cpp - Tests for ELFObjectFile --------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/Object/ELFObjectFile.h" 10 #include "llvm/Support/MemoryBuffer.h" 11 #include "llvm/ObjectYAML/yaml2obj.h" 12 #include "llvm/Support/YAMLTraits.h" 13 #include "llvm/Testing/Support/Error.h" 14 #include "gtest/gtest.h" 15 16 using namespace llvm; 17 using namespace llvm::object; 18 19 namespace { 20 21 // A struct to initialize a buffer to represent an ELF object file. 22 struct DataForTest { 23 std::vector<uint8_t> Data; 24 25 template <typename T> 26 std::vector<uint8_t> makeElfData(uint8_t Class, uint8_t Encoding, 27 uint16_t Machine) { 28 T Ehdr{}; // Zero-initialise the header. 29 Ehdr.e_ident[ELF::EI_MAG0] = 0x7f; 30 Ehdr.e_ident[ELF::EI_MAG1] = 'E'; 31 Ehdr.e_ident[ELF::EI_MAG2] = 'L'; 32 Ehdr.e_ident[ELF::EI_MAG3] = 'F'; 33 Ehdr.e_ident[ELF::EI_CLASS] = Class; 34 Ehdr.e_ident[ELF::EI_DATA] = Encoding; 35 Ehdr.e_ident[ELF::EI_VERSION] = 1; 36 Ehdr.e_type = ELF::ET_REL; 37 Ehdr.e_machine = Machine; 38 Ehdr.e_version = 1; 39 Ehdr.e_ehsize = sizeof(T); 40 41 bool IsLittleEndian = Encoding == ELF::ELFDATA2LSB; 42 if (sys::IsLittleEndianHost != IsLittleEndian) { 43 sys::swapByteOrder(Ehdr.e_type); 44 sys::swapByteOrder(Ehdr.e_machine); 45 sys::swapByteOrder(Ehdr.e_version); 46 sys::swapByteOrder(Ehdr.e_ehsize); 47 } 48 49 uint8_t *EhdrBytes = reinterpret_cast<uint8_t *>(&Ehdr); 50 std::vector<uint8_t> Bytes; 51 std::copy(EhdrBytes, EhdrBytes + sizeof(Ehdr), std::back_inserter(Bytes)); 52 return Bytes; 53 } 54 55 DataForTest(uint8_t Class, uint8_t Encoding, uint16_t Machine) { 56 if (Class == ELF::ELFCLASS64) 57 Data = makeElfData<ELF::Elf64_Ehdr>(Class, Encoding, Machine); 58 else { 59 assert(Class == ELF::ELFCLASS32); 60 Data = makeElfData<ELF::Elf32_Ehdr>(Class, Encoding, Machine); 61 } 62 } 63 }; 64 65 void checkFormatAndArch(const DataForTest &D, StringRef Fmt, 66 Triple::ArchType Arch) { 67 Expected<std::unique_ptr<ObjectFile>> ELFObjOrErr = 68 object::ObjectFile::createELFObjectFile( 69 MemoryBufferRef(toStringRef(D.Data), "dummyELF")); 70 ASSERT_THAT_EXPECTED(ELFObjOrErr, Succeeded()); 71 72 const ObjectFile &File = *(*ELFObjOrErr).get(); 73 EXPECT_EQ(Fmt, File.getFileFormatName()); 74 EXPECT_EQ(Arch, File.getArch()); 75 } 76 77 std::array<DataForTest, 4> generateData(uint16_t Machine) { 78 return {DataForTest(ELF::ELFCLASS32, ELF::ELFDATA2LSB, Machine), 79 DataForTest(ELF::ELFCLASS32, ELF::ELFDATA2MSB, Machine), 80 DataForTest(ELF::ELFCLASS64, ELF::ELFDATA2LSB, Machine), 81 DataForTest(ELF::ELFCLASS64, ELF::ELFDATA2MSB, Machine)}; 82 } 83 84 } // namespace 85 86 TEST(ELFObjectFileTest, MachineTestForNoneOrUnused) { 87 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown", 88 "elf64-unknown", "elf64-unknown"}; 89 size_t I = 0; 90 for (const DataForTest &D : generateData(ELF::EM_NONE)) 91 checkFormatAndArch(D, Formats[I++], Triple::UnknownArch); 92 93 // Test an arbitrary unused EM_* value (255). 94 I = 0; 95 for (const DataForTest &D : generateData(255)) 96 checkFormatAndArch(D, Formats[I++], Triple::UnknownArch); 97 } 98 99 TEST(ELFObjectFileTest, MachineTestForVE) { 100 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown", 101 "elf64-ve", "elf64-ve"}; 102 size_t I = 0; 103 for (const DataForTest &D : generateData(ELF::EM_VE)) 104 checkFormatAndArch(D, Formats[I++], Triple::ve); 105 } 106 107 TEST(ELFObjectFileTest, MachineTestForX86_64) { 108 std::array<StringRef, 4> Formats = {"elf32-x86-64", "elf32-x86-64", 109 "elf64-x86-64", "elf64-x86-64"}; 110 size_t I = 0; 111 for (const DataForTest &D : generateData(ELF::EM_X86_64)) 112 checkFormatAndArch(D, Formats[I++], Triple::x86_64); 113 } 114 115 TEST(ELFObjectFileTest, MachineTestFor386) { 116 std::array<StringRef, 4> Formats = {"elf32-i386", "elf32-i386", "elf64-i386", 117 "elf64-i386"}; 118 size_t I = 0; 119 for (const DataForTest &D : generateData(ELF::EM_386)) 120 checkFormatAndArch(D, Formats[I++], Triple::x86); 121 } 122 123 TEST(ELFObjectFileTest, MachineTestForMIPS) { 124 std::array<StringRef, 4> Formats = {"elf32-mips", "elf32-mips", "elf64-mips", 125 "elf64-mips"}; 126 std::array<Triple::ArchType, 4> Archs = {Triple::mipsel, Triple::mips, 127 Triple::mips64el, Triple::mips64}; 128 size_t I = 0; 129 for (const DataForTest &D : generateData(ELF::EM_MIPS)) { 130 checkFormatAndArch(D, Formats[I], Archs[I]); 131 ++I; 132 } 133 } 134 135 TEST(ELFObjectFileTest, MachineTestForAMDGPU) { 136 std::array<StringRef, 4> Formats = {"elf32-amdgpu", "elf32-amdgpu", 137 "elf64-amdgpu", "elf64-amdgpu"}; 138 size_t I = 0; 139 for (const DataForTest &D : generateData(ELF::EM_AMDGPU)) 140 checkFormatAndArch(D, Formats[I++], Triple::UnknownArch); 141 } 142 143 TEST(ELFObjectFileTest, MachineTestForIAMCU) { 144 std::array<StringRef, 4> Formats = {"elf32-iamcu", "elf32-iamcu", 145 "elf64-unknown", "elf64-unknown"}; 146 size_t I = 0; 147 for (const DataForTest &D : generateData(ELF::EM_IAMCU)) 148 checkFormatAndArch(D, Formats[I++], Triple::x86); 149 } 150 151 TEST(ELFObjectFileTest, MachineTestForAARCH64) { 152 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown", 153 "elf64-littleaarch64", 154 "elf64-bigaarch64"}; 155 std::array<Triple::ArchType, 4> Archs = {Triple::aarch64, Triple::aarch64_be, 156 Triple::aarch64, Triple::aarch64_be}; 157 size_t I = 0; 158 for (const DataForTest &D : generateData(ELF::EM_AARCH64)) { 159 checkFormatAndArch(D, Formats[I], Archs[I]); 160 ++I; 161 } 162 } 163 164 TEST(ELFObjectFileTest, MachineTestForPPC64) { 165 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown", 166 "elf64-powerpcle", "elf64-powerpc"}; 167 std::array<Triple::ArchType, 4> Archs = {Triple::ppc64le, Triple::ppc64, 168 Triple::ppc64le, Triple::ppc64}; 169 size_t I = 0; 170 for (const DataForTest &D : generateData(ELF::EM_PPC64)) { 171 checkFormatAndArch(D, Formats[I], Archs[I]); 172 ++I; 173 } 174 } 175 176 TEST(ELFObjectFileTest, MachineTestForPPC) { 177 std::array<StringRef, 4> Formats = {"elf32-powerpc", "elf32-powerpc", 178 "elf64-unknown", "elf64-unknown"}; 179 size_t I = 0; 180 for (const DataForTest &D : generateData(ELF::EM_PPC)) 181 checkFormatAndArch(D, Formats[I++], Triple::ppc); 182 } 183 184 TEST(ELFObjectFileTest, MachineTestForRISCV) { 185 std::array<StringRef, 4> Formats = {"elf32-littleriscv", "elf32-littleriscv", 186 "elf64-littleriscv", "elf64-littleriscv"}; 187 std::array<Triple::ArchType, 4> Archs = {Triple::riscv32, Triple::riscv32, 188 Triple::riscv64, Triple::riscv64}; 189 size_t I = 0; 190 for (const DataForTest &D : generateData(ELF::EM_RISCV)) { 191 checkFormatAndArch(D, Formats[I], Archs[I]); 192 ++I; 193 } 194 } 195 196 TEST(ELFObjectFileTest, MachineTestForARM) { 197 std::array<StringRef, 4> Formats = {"elf32-littlearm", "elf32-bigarm", 198 "elf64-unknown", "elf64-unknown"}; 199 size_t I = 0; 200 for (const DataForTest &D : generateData(ELF::EM_ARM)) 201 checkFormatAndArch(D, Formats[I++], Triple::arm); 202 } 203 204 TEST(ELFObjectFileTest, MachineTestForS390) { 205 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown", 206 "elf64-s390", "elf64-s390"}; 207 size_t I = 0; 208 for (const DataForTest &D : generateData(ELF::EM_S390)) 209 checkFormatAndArch(D, Formats[I++], Triple::systemz); 210 } 211 212 TEST(ELFObjectFileTest, MachineTestForSPARCV9) { 213 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown", 214 "elf64-sparc", "elf64-sparc"}; 215 size_t I = 0; 216 for (const DataForTest &D : generateData(ELF::EM_SPARCV9)) 217 checkFormatAndArch(D, Formats[I++], Triple::sparcv9); 218 } 219 220 TEST(ELFObjectFileTest, MachineTestForSPARC) { 221 std::array<StringRef, 4> Formats = {"elf32-sparc", "elf32-sparc", 222 "elf64-unknown", "elf64-unknown"}; 223 std::array<Triple::ArchType, 4> Archs = {Triple::sparcel, Triple::sparc, 224 Triple::sparcel, Triple::sparc}; 225 size_t I = 0; 226 for (const DataForTest &D : generateData(ELF::EM_SPARC)) { 227 checkFormatAndArch(D, Formats[I], Archs[I]); 228 ++I; 229 } 230 } 231 232 TEST(ELFObjectFileTest, MachineTestForSPARC32PLUS) { 233 std::array<StringRef, 4> Formats = {"elf32-sparc", "elf32-sparc", 234 "elf64-unknown", "elf64-unknown"}; 235 std::array<Triple::ArchType, 4> Archs = {Triple::sparcel, Triple::sparc, 236 Triple::sparcel, Triple::sparc}; 237 size_t I = 0; 238 for (const DataForTest &D : generateData(ELF::EM_SPARC32PLUS)) { 239 checkFormatAndArch(D, Formats[I], Archs[I]); 240 ++I; 241 } 242 } 243 244 TEST(ELFObjectFileTest, MachineTestForBPF) { 245 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown", 246 "elf64-bpf", "elf64-bpf"}; 247 std::array<Triple::ArchType, 4> Archs = {Triple::bpfel, Triple::bpfeb, 248 Triple::bpfel, Triple::bpfeb}; 249 size_t I = 0; 250 for (const DataForTest &D : generateData(ELF::EM_BPF)) { 251 checkFormatAndArch(D, Formats[I], Archs[I]); 252 ++I; 253 } 254 } 255 256 TEST(ELFObjectFileTest, MachineTestForAVR) { 257 std::array<StringRef, 4> Formats = {"elf32-avr", "elf32-avr", "elf64-unknown", 258 "elf64-unknown"}; 259 size_t I = 0; 260 for (const DataForTest &D : generateData(ELF::EM_AVR)) 261 checkFormatAndArch(D, Formats[I++], Triple::avr); 262 } 263 264 TEST(ELFObjectFileTest, MachineTestForHEXAGON) { 265 std::array<StringRef, 4> Formats = {"elf32-hexagon", "elf32-hexagon", 266 "elf64-unknown", "elf64-unknown"}; 267 size_t I = 0; 268 for (const DataForTest &D : generateData(ELF::EM_HEXAGON)) 269 checkFormatAndArch(D, Formats[I++], Triple::hexagon); 270 } 271 272 TEST(ELFObjectFileTest, MachineTestForLANAI) { 273 std::array<StringRef, 4> Formats = {"elf32-lanai", "elf32-lanai", 274 "elf64-unknown", "elf64-unknown"}; 275 size_t I = 0; 276 for (const DataForTest &D : generateData(ELF::EM_LANAI)) 277 checkFormatAndArch(D, Formats[I++], Triple::lanai); 278 } 279 280 TEST(ELFObjectFileTest, MachineTestForMSP430) { 281 std::array<StringRef, 4> Formats = {"elf32-msp430", "elf32-msp430", 282 "elf64-unknown", "elf64-unknown"}; 283 size_t I = 0; 284 for (const DataForTest &D : generateData(ELF::EM_MSP430)) 285 checkFormatAndArch(D, Formats[I++], Triple::msp430); 286 } 287 288 TEST(ELFObjectFileTest, MachineTestForCSKY) { 289 std::array<StringRef, 4> Formats = {"elf32-csky", "elf32-csky", 290 "elf64-unknown", "elf64-unknown"}; 291 size_t I = 0; 292 for (const DataForTest &D : generateData(ELF::EM_CSKY)) 293 checkFormatAndArch(D, Formats[I++], Triple::csky); 294 } 295 296 // ELF relative relocation type test. 297 TEST(ELFObjectFileTest, RelativeRelocationTypeTest) { 298 EXPECT_EQ(ELF::R_CKCORE_RELATIVE, getELFRelativeRelocationType(ELF::EM_CSKY)); 299 } 300 301 template <class ELFT> 302 static Expected<ELFObjectFile<ELFT>> toBinary(SmallVectorImpl<char> &Storage, 303 StringRef Yaml) { 304 raw_svector_ostream OS(Storage); 305 yaml::Input YIn(Yaml); 306 if (!yaml::convertYAML(YIn, OS, [](const Twine &Msg) {})) 307 return createStringError(std::errc::invalid_argument, 308 "unable to convert YAML"); 309 return ELFObjectFile<ELFT>::create(MemoryBufferRef(OS.str(), "dummyELF")); 310 } 311 312 // Check we are able to create an ELFObjectFile even when the content of the 313 // SHT_SYMTAB_SHNDX section can't be read properly. 314 TEST(ELFObjectFileTest, InvalidSymtabShndxTest) { 315 SmallString<0> Storage; 316 Expected<ELFObjectFile<ELF64LE>> ExpectedFile = toBinary<ELF64LE>(Storage, R"( 317 --- !ELF 318 FileHeader: 319 Class: ELFCLASS64 320 Data: ELFDATA2LSB 321 Type: ET_REL 322 Sections: 323 - Name: .symtab_shndx 324 Type: SHT_SYMTAB_SHNDX 325 Entries: [ 0 ] 326 ShSize: 0xFFFFFFFF 327 )"); 328 329 ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded()); 330 } 331