[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