Skip to content

Commit 85f4023

Browse files
npmillermstorsjo
authored andcommitted
[COFF] Move section name encoding into BinaryFormat
Large COFF section names are moved into the string table and the section header field is the offset into the string table encoded in ASCII for offset smaller than 7 digits and in base64 for larger offsets. The operation of taking the string table offsets is done in a few places in the codebase, so it is helpful to move this operation into `BinaryFormat` so that it can be shared everywhere it's done. So this patch takes the implementation of this operation from `llvm/lib/MC/WinCOFFObjectWriter.cpp` and moves it into `BinaryFormat`. Reviewed By: jhenderson, rnk Differential Revision: https://reviews.llvm.org/D118793
1 parent 9453cda commit 85f4023

File tree

4 files changed

+64
-39
lines changed

4 files changed

+64
-39
lines changed

llvm/include/llvm/BinaryFormat/COFF.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,10 @@ inline bool isReservedSectionNumber(int32_t SectionNumber) {
731731
return SectionNumber <= 0;
732732
}
733733

734+
/// Encode section name based on string table offset.
735+
/// The size of Out must be at least COFF::NameSize.
736+
bool encodeSectionName(char *Out, uint64_t Offset);
737+
734738
} // End namespace COFF.
735739
} // End namespace llvm.
736740

llvm/lib/BinaryFormat/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
add_llvm_component_library(LLVMBinaryFormat
22
AMDGPUMetadataVerifier.cpp
3+
COFF.cpp
34
Dwarf.cpp
45
ELF.cpp
56
MachO.cpp

llvm/lib/BinaryFormat/COFF.cpp

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

llvm/lib/MC/WinCOFFObjectWriter.cpp

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -451,52 +451,15 @@ void WinCOFFObjectWriter::DefineSymbol(const MCSymbol &MCSym,
451451
Sym->MC = &MCSym;
452452
}
453453

454-
// Maximum offsets for different string table entry encodings.
455-
enum : unsigned { Max7DecimalOffset = 9999999U };
456-
enum : uint64_t { MaxBase64Offset = 0xFFFFFFFFFULL }; // 64^6, including 0
457-
458-
// Encode a string table entry offset in base 64, padded to 6 chars, and
459-
// prefixed with a double slash: '//AAAAAA', '//AAAAAB', ...
460-
// Buffer must be at least 8 bytes large. No terminating null appended.
461-
static void encodeBase64StringEntry(char *Buffer, uint64_t Value) {
462-
assert(Value > Max7DecimalOffset && Value <= MaxBase64Offset &&
463-
"Illegal section name encoding for value");
464-
465-
static const char Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
466-
"abcdefghijklmnopqrstuvwxyz"
467-
"0123456789+/";
468-
469-
Buffer[0] = '/';
470-
Buffer[1] = '/';
471-
472-
char *Ptr = Buffer + 7;
473-
for (unsigned i = 0; i < 6; ++i) {
474-
unsigned Rem = Value % 64;
475-
Value /= 64;
476-
*(Ptr--) = Alphabet[Rem];
477-
}
478-
}
479-
480454
void WinCOFFObjectWriter::SetSectionName(COFFSection &S) {
481455
if (S.Name.size() <= COFF::NameSize) {
482456
std::memcpy(S.Header.Name, S.Name.c_str(), S.Name.size());
483457
return;
484458
}
485459

486460
uint64_t StringTableEntry = Strings.getOffset(S.Name);
487-
if (StringTableEntry <= Max7DecimalOffset) {
488-
SmallVector<char, COFF::NameSize> Buffer;
489-
Twine('/').concat(Twine(StringTableEntry)).toVector(Buffer);
490-
assert(Buffer.size() <= COFF::NameSize && Buffer.size() >= 2);
491-
std::memcpy(S.Header.Name, Buffer.data(), Buffer.size());
492-
return;
493-
}
494-
if (StringTableEntry <= MaxBase64Offset) {
495-
// Starting with 10,000,000, offsets are encoded as base64.
496-
encodeBase64StringEntry(S.Header.Name, StringTableEntry);
497-
return;
498-
}
499-
report_fatal_error("COFF string table is greater than 64 GB.");
461+
if (!COFF::encodeSectionName(S.Header.Name, StringTableEntry))
462+
report_fatal_error("COFF string table is greater than 64 GB.");
500463
}
501464

502465
void WinCOFFObjectWriter::SetSymbolName(COFFSymbol &S) {

0 commit comments

Comments
 (0)