[llvm-branch-commits] [llvm] [Offload] Make compressed offload bundle header little-endian (PR #206744)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Jun 30 07:58:54 PDT 2026


https://github.com/michaelselehov created https://github.com/llvm/llvm-project/pull/206744

The compressed offload bundle (CCOB) header integer fields (Magic, Version, Method, FileSize, UncompressedFileSize, Hash) were serialized and read in host-native byte order. The on-disk format is little-endian, so on big-endian hosts these fields were byte-swapped: writing produced a malformed header and reading misparsed the size, making llvm-objdump --offloading crash/misbehave on s390x.

Use support::ulittleN_t for the header fields on the read side and support::endian::Writer on the write side, so the header is always little-endian regardless of host endianness.

>From 473b717ca7d2f7bd2fa03c919ff322aa1095836a Mon Sep 17 00:00:00 2001
From: mselehov <mselehov at amd.com>
Date: Tue, 30 Jun 2026 09:13:05 -0500
Subject: [PATCH] [Offload] Make compressed offload bundle header little-endian

The compressed offload bundle (CCOB) header integer fields (Magic,
Version, Method, FileSize, UncompressedFileSize, Hash) were serialized
and read in host-native byte order. The on-disk format is little-endian,
so on big-endian hosts these fields were byte-swapped: writing produced a
malformed header and reading misparsed the size, making
llvm-objdump --offloading crash/misbehave on s390x.

Use support::ulittleN_t for the header fields on the read side and
support::endian::Writer on the write side, so the header is always
little-endian regardless of host endianness.

Co-authored-by: Nikita Popov <npopov at redhat.com>
---
 llvm/lib/Object/OffloadBundle.cpp | 49 ++++++++++++++-----------------
 1 file changed, 22 insertions(+), 27 deletions(-)

diff --git a/llvm/lib/Object/OffloadBundle.cpp b/llvm/lib/Object/OffloadBundle.cpp
index 93fb2ab1affc7..c178411c9a641 100644
--- a/llvm/lib/Object/OffloadBundle.cpp
+++ b/llvm/lib/Object/OffloadBundle.cpp
@@ -19,6 +19,7 @@
 #include "llvm/Object/IRObjectFile.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/EndianStream.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Support/Timer.h"
 
@@ -372,28 +373,22 @@ CompressedOffloadBundle::compress(compression::Params P,
 
   SmallVector<char, 0> FinalBuffer;
   raw_svector_ostream OS(FinalBuffer);
+  // The on-disk header is always little-endian, independent of the host.
+  support::endian::Writer Writer(OS, endianness::little);
   OS << MagicNumber;
-  OS.write(reinterpret_cast<const char *>(&Version), sizeof(Version));
-  OS.write(reinterpret_cast<const char *>(&CompressionMethod),
-           sizeof(CompressionMethod));
+  Writer.write(Version);
+  Writer.write(CompressionMethod);
 
   // Write size fields according to version.
   if (Version == 2) {
-    uint32_t TotalFileSize32 = static_cast<uint32_t>(TotalFileSize64);
-    uint32_t UncompressedSize32 = static_cast<uint32_t>(UncompressedSize64);
-    OS.write(reinterpret_cast<const char *>(&TotalFileSize32),
-             sizeof(TotalFileSize32));
-    OS.write(reinterpret_cast<const char *>(&UncompressedSize32),
-             sizeof(UncompressedSize32));
+    Writer.write(static_cast<uint32_t>(TotalFileSize64));
+    Writer.write(static_cast<uint32_t>(UncompressedSize64));
   } else { // Version 3.
-    OS.write(reinterpret_cast<const char *>(&TotalFileSize64),
-             sizeof(TotalFileSize64));
-    OS.write(reinterpret_cast<const char *>(&UncompressedSize64),
-             sizeof(UncompressedSize64));
+    Writer.write(TotalFileSize64);
+    Writer.write(UncompressedSize64);
   }
 
-  OS.write(reinterpret_cast<const char *>(&TruncatedHash),
-           sizeof(TruncatedHash));
+  Writer.write(TruncatedHash);
   OS.write(reinterpret_cast<const char *>(CompressedBuffer.data()),
            CompressedBuffer.size());
 
@@ -432,29 +427,29 @@ CompressedOffloadBundle::compress(compression::Params P,
 LLVM_PACKED_START
 union RawCompressedBundleHeader {
   struct CommonFields {
-    uint32_t Magic;
-    uint16_t Version;
-    uint16_t Method;
+    support::ulittle32_t Magic;
+    support::ulittle16_t Version;
+    support::ulittle16_t Method;
   };
 
   struct V1Header {
     CommonFields Common;
-    uint32_t UncompressedFileSize;
-    uint64_t Hash;
+    support::ulittle32_t UncompressedFileSize;
+    support::ulittle64_t Hash;
   };
 
   struct V2Header {
     CommonFields Common;
-    uint32_t FileSize;
-    uint32_t UncompressedFileSize;
-    uint64_t Hash;
+    support::ulittle32_t FileSize;
+    support::ulittle32_t UncompressedFileSize;
+    support::ulittle64_t Hash;
   };
 
   struct V3Header {
     CommonFields Common;
-    uint64_t FileSize;
-    uint64_t UncompressedFileSize;
-    uint64_t Hash;
+    support::ulittle64_t FileSize;
+    support::ulittle64_t UncompressedFileSize;
+    support::ulittle64_t Hash;
   };
 
   CommonFields Common;
@@ -518,7 +513,7 @@ CompressedOffloadBundle::CompressedBundleHeader::tryParse(StringRef Blob) {
   case static_cast<uint16_t>(compression::Format::Zlib):
   case static_cast<uint16_t>(compression::Format::Zstd):
     Normalized.CompressionFormat =
-        static_cast<compression::Format>(Header.Common.Method);
+        static_cast<compression::Format>(Header.Common.Method.value());
     break;
   default:
     return createStringError("unknown compressing method");



More information about the llvm-branch-commits mailing list