[llvm] New tool 'llvm-elf2bin'. (NOT READY FOR REVIEW – NO TESTS) (PR #73625)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 28 08:18:16 PST 2023


================
@@ -0,0 +1,326 @@
+//===- bin.cpp - Code to write binary and VHX output for llvm-elf2bin -----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-elf2bin.h"
+
+#include <algorithm>
+#include <cassert>
+#include <memory>
+#include <queue>
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/bit.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+/*
+ * Abstraction that provides a means of getting binary data from
+ * somewhere. In the simple case this will involve reading data from a
+ * segment in an ELF file. In more complex cases there might also be
+ * zero-byte padding, or one of these stream objects filtering out the
+ * even-index bytes of another.
+ */
+class BinaryDataStream {
+public:
+  // Returns a string of data, in whatever size is convenient. (But
+  // the size should be bounded, so that other streams filtering this
+  // one don't have to swallow a whole file in one go.)
+  //
+  // An empty returned string means EOF.
+  virtual StringRef read() = 0;
+  virtual ~BinaryDataStream() = default;
+};
+
+/*
+ * BinaryDataStream implementation that reads data from an ELF image.
+ */
+class ElfSegment : public BinaryDataStream {
+  InputObject &inobj;
+  size_t position, remaining;
+
+  StringRef read() override {
+    size_t readlen = std::min<size_t>(remaining, 65536);
+    size_t readpos = position;
+    position += readlen;
+    remaining -= readlen;
+    return inobj.membuf->getBuffer().substr(readpos, readlen);
+  }
+
+public:
+  ElfSegment(InputObject &inobj, size_t offset, size_t size)
+      : inobj(inobj), position(offset), remaining(size) {}
+};
+
+/*
+ * BinaryDataStream implementation that generates zero padding.
+ */
+class Padding : public BinaryDataStream {
+  size_t remaining;
+  char buffer[65536];
+
+  StringRef read() override {
+    size_t readlen = std::min<size_t>(remaining, 65536);
+    remaining -= readlen;
+    return StringRef(buffer, readlen);
+  }
+
+public:
+  Padding(size_t size) : remaining(size) { memset(buffer, 0, sizeof(buffer)); }
+};
+
+/*
+ * BinaryDataStream implementation that chains other BinaryDataStreams
+ * together.
+ */
+class Chain : public BinaryDataStream {
+  std::queue<std::unique_ptr<BinaryDataStream>> queue;
+
+  StringRef read() override {
+    while (!queue.empty()) {
+      StringRef data = queue.front()->read();
+      if (!data.empty())
+        return data;
+
+      queue.pop();
+    }
+
+    // If we get here, everything in our queue has finished.
+    return "";
+  }
+
+public:
+  Chain() = default;
+  void push(std::unique_ptr<BinaryDataStream> &&st) {
+    queue.push(std::move(st));
+  }
+};
+
+/*
+ * BinaryDataStream implementation that filters the output of another
+ * BinaryDataStream so as to return only a subset of the bytes,
+ * defined by a modulus and a range of residues. Specifically, a range
+ * of 'nres' consecutive bytes from the underlying stream is passed
+ * on, beginning at each byte whose index is congruent to 'firstres'
+ * mod 'modulus' (regarding the first byte of the underlying stream as
+ * having index 0).
+ *
+ * 'modulus' has to be a power of 2.
+ */
+class ModFilter : public BinaryDataStream {
+  std::unique_ptr<BinaryDataStream> st;
+  // Internal representation: 'mask' is the bitmask that reduces mod
+  // 'modulus'. 'pos' iterates cyclically over 0,...,modulus-1 with
+  // each byte we consume, and we return the byte if pos < nres.
+  uint64_t mask, nres, pos;
+  std::string outstring;
+
+  StringRef read() override {
+    outstring.clear();
+    llvm::raw_string_ostream outstream(outstring);
+
+    while (true) {
+      StringRef data = st->read();
+      if (data.empty())
+        break;
+
+      for (char c : data) {
+        if (pos < nres)
+          outstream << c;
+        pos = (pos + 1) & mask;
+      }
+
+      // If that batch of input contributed no bytes to our
+      // output, go round again. Otherwise, we have something to
+      // return.
+      if (!outstring.empty())
+        break;
+    }
+    return outstring;
+  }
+
+public:
+  ModFilter(std::unique_ptr<BinaryDataStream> &&st, uint64_t modulus,
+            uint64_t firstres, uint64_t nres)
+      : st(std::move(st)), nres(nres) {
+    // Check input values are reasonable.
+    assert(llvm::has_single_bit(modulus));
+    assert(nres > 0);
+    assert(nres < modulus);
+
+    mask = modulus - 1;
+
+    // Set pos to be (-firstres), so that we'll skip the right
+    // number of bytes before the first one we return.
+    //
+    // Written as (1 + ~firstres) to avoid Visual Studio
+    // complaining about negating an unsigned.
+    pos = (1 + ~firstres) & mask;
----------------
MaskRay wrote:

There are many places where we would cause MSVC `warning C4146: unary minus operator applied to unsigned type, result still unsigned`. We have `/wd4146` in `compiler-rt/cmake/config-ix.cmake` and should just use `-` without needing a comment.

https://github.com/llvm/llvm-project/pull/73625


More information about the llvm-commits mailing list