xref: /llvm-project/llvm/lib/BinaryFormat/COFF.cpp (revision 85f4023e731c0c42e45bf32bfcbf5f73c2013384)
1*85f4023eSNicolas Miller //===- llvm/BinaryFormat/COFF.cpp - The COFF format -----------------------===//
2*85f4023eSNicolas Miller //
3*85f4023eSNicolas Miller // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*85f4023eSNicolas Miller // See https://llvm.org/LICENSE.txt for license information.
5*85f4023eSNicolas Miller // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*85f4023eSNicolas Miller //
7*85f4023eSNicolas Miller //===----------------------------------------------------------------------===//
8*85f4023eSNicolas Miller 
9*85f4023eSNicolas Miller #include "llvm/BinaryFormat/COFF.h"
10*85f4023eSNicolas Miller #include "llvm/ADT/SmallVector.h"
11*85f4023eSNicolas Miller #include "llvm/ADT/Twine.h"
12*85f4023eSNicolas Miller 
13*85f4023eSNicolas Miller // Maximum offsets for different string table entry encodings.
14*85f4023eSNicolas Miller enum : unsigned { Max7DecimalOffset = 9999999U };
15*85f4023eSNicolas Miller enum : uint64_t { MaxBase64Offset = 0xFFFFFFFFFULL }; // 64^6, including 0
16*85f4023eSNicolas Miller 
17*85f4023eSNicolas Miller // Encode a string table entry offset in base 64, padded to 6 chars, and
18*85f4023eSNicolas Miller // prefixed with a double slash: '//AAAAAA', '//AAAAAB', ...
19*85f4023eSNicolas Miller // Buffer must be at least 8 bytes large. No terminating null appended.
encodeBase64StringEntry(char * Buffer,uint64_t Value)20*85f4023eSNicolas Miller static void encodeBase64StringEntry(char *Buffer, uint64_t Value) {
21*85f4023eSNicolas Miller   assert(Value > Max7DecimalOffset && Value <= MaxBase64Offset &&
22*85f4023eSNicolas Miller          "Illegal section name encoding for value");
23*85f4023eSNicolas Miller 
24*85f4023eSNicolas Miller   static const char Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
25*85f4023eSNicolas Miller                                  "abcdefghijklmnopqrstuvwxyz"
26*85f4023eSNicolas Miller                                  "0123456789+/";
27*85f4023eSNicolas Miller 
28*85f4023eSNicolas Miller   Buffer[0] = '/';
29*85f4023eSNicolas Miller   Buffer[1] = '/';
30*85f4023eSNicolas Miller 
31*85f4023eSNicolas Miller   char *Ptr = Buffer + 7;
32*85f4023eSNicolas Miller   for (unsigned i = 0; i < 6; ++i) {
33*85f4023eSNicolas Miller     unsigned Rem = Value % 64;
34*85f4023eSNicolas Miller     Value /= 64;
35*85f4023eSNicolas Miller     *(Ptr--) = Alphabet[Rem];
36*85f4023eSNicolas Miller   }
37*85f4023eSNicolas Miller }
38*85f4023eSNicolas Miller 
encodeSectionName(char * Out,uint64_t Offset)39*85f4023eSNicolas Miller bool llvm::COFF::encodeSectionName(char *Out, uint64_t Offset) {
40*85f4023eSNicolas Miller   if (Offset <= Max7DecimalOffset) {
41*85f4023eSNicolas Miller     // Offsets of 7 digits or less are encoded in ASCII.
42*85f4023eSNicolas Miller     SmallVector<char, COFF::NameSize> Buffer;
43*85f4023eSNicolas Miller     Twine('/').concat(Twine(Offset)).toVector(Buffer);
44*85f4023eSNicolas Miller     assert(Buffer.size() <= COFF::NameSize && Buffer.size() >= 2);
45*85f4023eSNicolas Miller     std::memcpy(Out, Buffer.data(), Buffer.size());
46*85f4023eSNicolas Miller     return true;
47*85f4023eSNicolas Miller   }
48*85f4023eSNicolas Miller 
49*85f4023eSNicolas Miller   if (Offset <= MaxBase64Offset) {
50*85f4023eSNicolas Miller     // Starting with 10,000,000, offsets are encoded as base64.
51*85f4023eSNicolas Miller     encodeBase64StringEntry(Out, Offset);
52*85f4023eSNicolas Miller     return true;
53*85f4023eSNicolas Miller   }
54*85f4023eSNicolas Miller 
55*85f4023eSNicolas Miller   // The offset is too large to be encoded.
56*85f4023eSNicolas Miller   return false;
57*85f4023eSNicolas Miller }
58