Skip to content

Commit 3b337bb

Browse files
authored
[ELF] Attempt to set the OS when using 'makeTriple()' (#76992)
Summary: This patch fixes up the `makeTriple()` interface to emit append the operating system information when it is readily avaialble from the ELF. The main motivation for this is so the GPU architectures can be easily identified correctly when given and ELF. E.g. we want `amdgpu-amd-amdhsa` as the output and not `amdgpu--`. This required adding support for the CUDA OS/ABI, which is easily found to be `0x33` when using `readelf`.
1 parent 5352ce3 commit 3b337bb

File tree

6 files changed

+80
-9
lines changed

6 files changed

+80
-9
lines changed

llvm/include/llvm/BinaryFormat/ELF.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ enum {
356356
ELFOSABI_AROS = 15, // AROS
357357
ELFOSABI_FENIXOS = 16, // FenixOS
358358
ELFOSABI_CLOUDABI = 17, // Nuxi CloudABI
359+
ELFOSABI_CUDA = 51, // NVIDIA CUDA architecture.
359360
ELFOSABI_FIRST_ARCH = 64, // First architecture-specific OS ABI
360361
ELFOSABI_AMDGPU_HSA = 64, // AMD HSA runtime
361362
ELFOSABI_AMDGPU_PAL = 65, // AMD PAL runtime

llvm/include/llvm/Object/ELFObjectFile.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase {
454454
uint8_t getBytesInAddress() const override;
455455
StringRef getFileFormatName() const override;
456456
Triple::ArchType getArch() const override;
457+
Triple::OSType getOS() const override;
457458
Expected<uint64_t> getStartAddress() const override;
458459

459460
unsigned getPlatformFlags() const override { return EF.getHeader().e_flags; }
@@ -1382,6 +1383,35 @@ template <class ELFT> Triple::ArchType ELFObjectFile<ELFT>::getArch() const {
13821383
}
13831384
}
13841385

1386+
template <class ELFT> Triple::OSType ELFObjectFile<ELFT>::getOS() const {
1387+
switch (EF.getHeader().e_ident[ELF::EI_OSABI]) {
1388+
case ELF::ELFOSABI_NETBSD:
1389+
return Triple::NetBSD;
1390+
case ELF::ELFOSABI_LINUX:
1391+
return Triple::Linux;
1392+
case ELF::ELFOSABI_HURD:
1393+
return Triple::Hurd;
1394+
case ELF::ELFOSABI_SOLARIS:
1395+
return Triple::Solaris;
1396+
case ELF::ELFOSABI_AIX:
1397+
return Triple::AIX;
1398+
case ELF::ELFOSABI_FREEBSD:
1399+
return Triple::FreeBSD;
1400+
case ELF::ELFOSABI_OPENBSD:
1401+
return Triple::OpenBSD;
1402+
case ELF::ELFOSABI_CUDA:
1403+
return Triple::CUDA;
1404+
case ELF::ELFOSABI_AMDGPU_HSA:
1405+
return Triple::AMDHSA;
1406+
case ELF::ELFOSABI_AMDGPU_PAL:
1407+
return Triple::AMDPAL;
1408+
case ELF::ELFOSABI_AMDGPU_MESA3D:
1409+
return Triple::Mesa3D;
1410+
default:
1411+
return Triple::UnknownOS;
1412+
}
1413+
}
1414+
13851415
template <class ELFT>
13861416
Expected<uint64_t> ELFObjectFile<ELFT>::getStartAddress() const {
13871417
return EF.getHeader().e_entry;

llvm/include/llvm/Object/ObjectFile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ class ObjectFile : public SymbolicFile {
337337

338338
virtual StringRef getFileFormatName() const = 0;
339339
virtual Triple::ArchType getArch() const = 0;
340+
virtual Triple::OSType getOS() const { return Triple::UnknownOS; }
340341
virtual Expected<SubtargetFeatures> getFeatures() const = 0;
341342
virtual std::optional<StringRef> tryGetCPUName() const {
342343
return std::nullopt;

llvm/lib/Object/ObjectFile.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ Triple ObjectFile::makeTriple() const {
111111
auto Arch = getArch();
112112
TheTriple.setArch(Triple::ArchType(Arch));
113113

114+
auto OS = getOS();
115+
if (OS != Triple::UnknownOS)
116+
TheTriple.setOS(OS);
117+
114118
// For ARM targets, try to use the build attributes to build determine
115119
// the build target. Target features are also added, but later during
116120
// disassembly.
@@ -129,10 +133,13 @@ Triple ObjectFile::makeTriple() const {
129133
// XCOFF implies AIX.
130134
TheTriple.setOS(Triple::AIX);
131135
TheTriple.setObjectFormat(Triple::XCOFF);
132-
}
133-
else if (isGOFF()) {
136+
} else if (isGOFF()) {
134137
TheTriple.setOS(Triple::ZOS);
135138
TheTriple.setObjectFormat(Triple::GOFF);
139+
} else if (TheTriple.isAMDGPU()) {
140+
TheTriple.setVendor(Triple::AMD);
141+
} else if (TheTriple.isNVPTX()) {
142+
TheTriple.setVendor(Triple::NVIDIA);
136143
}
137144

138145
return TheTriple;

llvm/tools/llvm-readobj/ELFDumper.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,7 @@ const EnumEntry<unsigned> ElfOSABI[] = {
10841084
{"AROS", "AROS", ELF::ELFOSABI_AROS},
10851085
{"FenixOS", "FenixOS", ELF::ELFOSABI_FENIXOS},
10861086
{"CloudABI", "CloudABI", ELF::ELFOSABI_CLOUDABI},
1087+
{"CUDA", "NVIDIA - CUDA", ELF::ELFOSABI_CUDA},
10871088
{"Standalone", "Standalone App", ELF::ELFOSABI_STANDALONE}
10881089
};
10891090

@@ -1093,6 +1094,10 @@ const EnumEntry<unsigned> AMDGPUElfOSABI[] = {
10931094
{"AMDGPU_MESA3D", "AMDGPU - MESA3D", ELF::ELFOSABI_AMDGPU_MESA3D}
10941095
};
10951096

1097+
const EnumEntry<unsigned> NVPTXElfOSABI[] = {
1098+
{"NVIDIA_CUDA", "NVIDIA - CUDA", ELF::ELFOSABI_CUDA},
1099+
};
1100+
10961101
const EnumEntry<unsigned> ARMElfOSABI[] = {
10971102
{"ARM", "ARM", ELF::ELFOSABI_ARM}
10981103
};

llvm/unittests/Object/ELFObjectFileTest.cpp

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ struct DataForTest {
3636

3737
template <typename T>
3838
std::vector<uint8_t> makeElfData(uint8_t Class, uint8_t Encoding,
39-
uint16_t Machine) {
39+
uint16_t Machine, uint8_t OS,
40+
uint16_t Flags) {
4041
T Ehdr{}; // Zero-initialise the header.
4142
Ehdr.e_ident[ELF::EI_MAG0] = 0x7f;
4243
Ehdr.e_ident[ELF::EI_MAG1] = 'E';
@@ -45,9 +46,11 @@ struct DataForTest {
4546
Ehdr.e_ident[ELF::EI_CLASS] = Class;
4647
Ehdr.e_ident[ELF::EI_DATA] = Encoding;
4748
Ehdr.e_ident[ELF::EI_VERSION] = 1;
49+
Ehdr.e_ident[ELF::EI_OSABI] = OS;
4850
Ehdr.e_type = ELF::ET_REL;
4951
Ehdr.e_machine = Machine;
5052
Ehdr.e_version = 1;
53+
Ehdr.e_flags = Flags;
5154
Ehdr.e_ehsize = sizeof(T);
5255

5356
bool IsLittleEndian = Encoding == ELF::ELFDATA2LSB;
@@ -64,12 +67,13 @@ struct DataForTest {
6467
return Bytes;
6568
}
6669

67-
DataForTest(uint8_t Class, uint8_t Encoding, uint16_t Machine) {
70+
DataForTest(uint8_t Class, uint8_t Encoding, uint16_t Machine,
71+
uint8_t OS = ELF::ELFOSABI_NONE, uint16_t Flags = 0) {
6872
if (Class == ELF::ELFCLASS64)
69-
Data = makeElfData<ELF::Elf64_Ehdr>(Class, Encoding, Machine);
73+
Data = makeElfData<ELF::Elf64_Ehdr>(Class, Encoding, Machine, OS, Flags);
7074
else {
7175
assert(Class == ELF::ELFCLASS32);
72-
Data = makeElfData<ELF::Elf32_Ehdr>(Class, Encoding, Machine);
76+
Data = makeElfData<ELF::Elf32_Ehdr>(Class, Encoding, Machine, OS, Flags);
7377
}
7478
}
7579
};
@@ -287,6 +291,30 @@ TEST(ELFObjectFileTest, MachineTestForXtensa) {
287291
checkFormatAndArch(Data, Formats[Idx], Triple::xtensa);
288292
}
289293

294+
TEST(ELFObjectFileTest, CheckOSAndTriple) {
295+
std::tuple<uint16_t, uint8_t, StringRef> Formats[] = {
296+
{ELF::EM_AMDGPU, ELF::ELFOSABI_AMDGPU_HSA, "amdgcn-amd-amdhsa"},
297+
{ELF::EM_X86_64, ELF::ELFOSABI_LINUX, "x86_64--linux"},
298+
{ELF::EM_X86_64, ELF::ELFOSABI_NETBSD, "x86_64--netbsd"},
299+
{ELF::EM_X86_64, ELF::ELFOSABI_HURD, "x86_64--hurd"},
300+
{ELF::EM_X86_64, ELF::ELFOSABI_SOLARIS, "x86_64--solaris"},
301+
{ELF::EM_X86_64, ELF::ELFOSABI_AIX, "x86_64--aix"},
302+
{ELF::EM_X86_64, ELF::ELFOSABI_FREEBSD, "x86_64--freebsd"},
303+
{ELF::EM_X86_64, ELF::ELFOSABI_OPENBSD, "x86_64--openbsd"},
304+
{ELF::EM_CUDA, ELF::ELFOSABI_CUDA, "nvptx64-nvidia-cuda"}};
305+
for (auto [Machine, OS, Triple] : Formats) {
306+
const DataForTest D(ELF::ELFCLASS64, ELF::ELFDATA2LSB, Machine, OS,
307+
ELF::EF_AMDGPU_MACH_AMDGCN_LAST);
308+
Expected<std::unique_ptr<ObjectFile>> ELFObjOrErr =
309+
object::ObjectFile::createELFObjectFile(
310+
MemoryBufferRef(toStringRef(D.Data), "dummyELF"));
311+
ASSERT_THAT_EXPECTED(ELFObjOrErr, Succeeded());
312+
313+
auto &ELFObj = **ELFObjOrErr;
314+
EXPECT_EQ(Triple, ELFObj.makeTriple().getTriple());
315+
}
316+
}
317+
290318
// ELF relative relocation type test.
291319
TEST(ELFObjectFileTest, RelativeRelocationTypeTest) {
292320
EXPECT_EQ(ELF::R_CKCORE_RELATIVE, getELFRelativeRelocationType(ELF::EM_CSKY));
@@ -1273,13 +1301,12 @@ TEST(ELFObjectFileTest, GetSectionAndRelocations) {
12731301
)";
12741302

12751303
auto ErroringMatcher = [](const Elf_Shdr &Sec) -> Expected<bool> {
1276-
if(Sec.sh_type == ELF::SHT_PROGBITS)
1304+
if (Sec.sh_type == ELF::SHT_PROGBITS)
12771305
return createError("This was supposed to fail.");
12781306
return false;
12791307
};
12801308

1281-
DoCheckFails(OneTextSection, ErroringMatcher,
1282-
"This was supposed to fail.");
1309+
DoCheckFails(OneTextSection, ErroringMatcher, "This was supposed to fail.");
12831310

12841311
StringRef MissingRelocatableContent = R"(
12851312
Sections:

0 commit comments

Comments
 (0)