Commit 91a3e2c9 by Jan Voung

Subzero: Write float/double constant pools directly to the ELF file.

Create the section, write the data and define the symbols in the symbol table. BUG=none R=stichnot@chromium.org Review URL: https://codereview.chromium.org/837393005
parent 7e571364
......@@ -17,6 +17,7 @@
#include "IceELFStreamer.h"
#include "IceGlobalContext.h"
#include "IceGlobalInits.h"
#include "IceOperand.h"
using namespace llvm::ELF;
......@@ -291,6 +292,61 @@ void ELFObjectWriter::writeELFHeaderInternal(Elf64_Off SectionHeaderOffset,
Str.writeLE16(static_cast<Elf64_Half>(SectHeaderStrIndex)); // e_shstrndx
}
template <typename ConstType> void ELFObjectWriter::writeConstantPool(Type Ty) {
ConstantList Pool = Ctx.getConstantPool(Ty);
if (Pool.empty()) {
return;
}
SizeT Align = typeAlignInBytes(Ty);
size_t EntSize = typeWidthInBytes(Ty);
char Buf[20];
SizeT WriteAmt = std::min(EntSize, llvm::array_lengthof(Buf));
assert(WriteAmt == EntSize);
// Assume that writing WriteAmt bytes at a time allows us to avoid aligning
// between entries.
assert(WriteAmt % Align == 0);
// Check that we write the full PrimType.
assert(WriteAmt == sizeof(typename ConstType::PrimType));
const Elf64_Xword ShFlags = SHF_ALLOC | SHF_MERGE;
std::string SecBuffer;
llvm::raw_string_ostream SecStrBuf(SecBuffer);
SecStrBuf << ".rodata.cst" << WriteAmt;
ELFDataSection *Section = createSection<ELFDataSection>(
SecStrBuf.str(), SHT_PROGBITS, ShFlags, Align, WriteAmt);
RoDataSections.push_back(Section);
SizeT OffsetInSection = 0;
// The symbol table entry doesn't need to know the defined symbol's
// size since this is in a section with a fixed Entry Size.
const SizeT SymbolSize = 0;
Section->setFileOffset(alignFileOffset(Align));
// Write the data.
for (Constant *C : Pool) {
auto Const = llvm::cast<ConstType>(C);
std::string SymBuffer;
llvm::raw_string_ostream SymStrBuf(SymBuffer);
SymStrBuf << ".L$" << Ty << "$" << Const->getPoolEntryID();
std::string &SymName = SymStrBuf.str();
SymTab->createDefinedSym(SymName, STT_NOTYPE, STB_LOCAL, Section,
OffsetInSection, SymbolSize);
StrTab->add(SymName);
typename ConstType::PrimType Value = Const->getValue();
memcpy(Buf, &Value, WriteAmt);
Str.writeBytes(llvm::StringRef(Buf, WriteAmt));
OffsetInSection += WriteAmt;
}
Section->setSize(OffsetInSection);
}
// Instantiate known needed versions of the template, since we are
// defining the function in the .cpp file instead of the .h file.
// We may need to instantiate constant pools for integers as well
// if we do constant-pooling of large integers to remove them
// from the instruction stream (fewer bytes controlled by an attacker).
template void ELFObjectWriter::writeConstantPool<ConstantFloat>(Type Ty);
template void ELFObjectWriter::writeConstantPool<ConstantDouble>(Type Ty);
void ELFObjectWriter::writeNonUserSections() {
bool IsELF64 = isELF64(Ctx.getTargetArch());
......
......@@ -17,6 +17,7 @@
#include "IceDefs.h"
#include "IceELFSection.h"
#include "IceELFStreamer.h"
#include "IceTypes.h"
using namespace llvm::ELF;
......@@ -59,6 +60,8 @@ public:
void writeDataInitializer(const IceString &VarName,
const llvm::StringRef Data);
template <typename ConstType> void writeConstantPool(Type Ty);
// Do final layout and write out the rest of the object file, then
// patch up the initial ELF header with the final info.
void writeNonUserSections();
......
......@@ -132,14 +132,16 @@ class ConstantPrimitive : public Constant {
ConstantPrimitive &operator=(const ConstantPrimitive &) = delete;
public:
static ConstantPrimitive *create(GlobalContext *Ctx, Type Ty, T Value,
typedef T PrimType;
static ConstantPrimitive *create(GlobalContext *Ctx, Type Ty, PrimType Value,
uint32_t PoolEntryID) {
assert(!Ctx->isIRGenerationDisabled() &&
"Attempt to build primitive constant when IR generation disabled");
return new (Ctx->allocate<ConstantPrimitive>())
ConstantPrimitive(Ty, Value, PoolEntryID);
}
T getValue() const { return Value; }
PrimType getValue() const { return Value; }
using Constant::emit;
// The target needs to implement this for each ConstantPrimitive
// specialization.
......@@ -155,10 +157,10 @@ public:
}
private:
ConstantPrimitive(Type Ty, T Value, uint32_t PoolEntryID)
ConstantPrimitive(Type Ty, PrimType Value, uint32_t PoolEntryID)
: Constant(K, Ty, PoolEntryID), Value(Value) {}
~ConstantPrimitive() override {}
const T Value;
const PrimType Value;
};
typedef ConstantPrimitive<int32_t, Operand::kConstInteger32> ConstantInteger32;
......
......@@ -967,7 +967,6 @@ void TargetX8632::addEpilog(CfgNode *Node) {
template <typename T> struct PoolTypeConverter {};
template <> struct PoolTypeConverter<float> {
typedef float PrimitiveFpType;
typedef uint32_t PrimitiveIntType;
typedef ConstantFloat IceType;
static const Type Ty = IceType_f32;
......@@ -980,7 +979,6 @@ const char *PoolTypeConverter<float>::AsmTag = ".long";
const char *PoolTypeConverter<float>::PrintfString = "0x%x";
template <> struct PoolTypeConverter<double> {
typedef double PrimitiveFpType;
typedef uint64_t PrimitiveIntType;
typedef ConstantDouble IceType;
static const Type Ty = IceType_f64;
......@@ -1004,7 +1002,7 @@ template <typename T> void TargetX8632::emitConstantPool() const {
Str << "\t.align\t" << Align << "\n";
for (Constant *C : Pool) {
typename T::IceType *Const = llvm::cast<typename T::IceType>(C);
typename T::PrimitiveFpType Value = Const->getValue();
typename T::IceType::PrimType Value = Const->getValue();
// Use memcpy() to copy bits from Value into RawValue in a way
// that avoids breaking strict-aliasing rules.
typename T::PrimitiveIntType RawValue;
......@@ -1022,12 +1020,16 @@ template <typename T> void TargetX8632::emitConstantPool() const {
}
void TargetX8632::emitConstants() const {
// Note: Still used by emit IAS.
// No need to emit constants from the int pool since (for x86) they
// are embedded as immediates in the instructions, just emit float/double.
if (Ctx->getFlags().UseELFWriter) {
ELFObjectWriter *Writer = Ctx->getObjectWriter();
Writer->writeConstantPool<ConstantFloat>(IceType_f32);
Writer->writeConstantPool<ConstantDouble>(IceType_f64);
} else {
emitConstantPool<PoolTypeConverter<float>>();
emitConstantPool<PoolTypeConverter<double>>();
// No need to emit constants from the int pool since (for x86) they
// are embedded as immediates in the instructions.
}
}
void TargetX8632::split64(Variable *Var) {
......
......@@ -97,13 +97,8 @@ void Translator::translateFcn(Cfg *Fcn) {
}
void Translator::emitConstants() {
if (!Ctx->getFlags().DisableTranslation && Func) {
if (Ctx->getFlags().UseELFWriter) {
// TODO(jvoung): create the rodata.cst.{4,8} sections for UseELFWriter.
} else {
if (!Ctx->getFlags().DisableTranslation && Func)
Func->getTarget()->emitConstants();
}
}
}
void Translator::lowerGlobals(
......
......@@ -38,14 +38,15 @@ declare void @llvm.memset.p0i8.i32(i8*, i8, i32, i32, i1)
; Use float/double constants to test constant pools.
define internal float @returnFloatConst() {
entry:
%f = fadd float 0x3FF3AE1480000000, 0x3FF3AE1400000000
%f = fadd float -0.0, 0x3FF3AE1400000000
ret float %f
}
define internal double @returnDoubleConst() {
entry:
%d = fadd double 1.230000e+00, 3.210000e+00
ret double %d
%d = fadd double 0x7FFFFFFFFFFFFFFFF, 0xFFF7FFFFFFFFFFFF
%d2 = fadd double %d, 0xFFF8000000000003
ret double %d2
}
define internal void @test_memcpy(i32 %iptr_dst, i32 %len) {
......@@ -141,6 +142,45 @@ define void @_start(i32) {
; CHECK: }
; CHECK: Section {
; CHECK: Index: {{[1-9][0-9]*}}
; CHECK: Name: .rodata.cst4
; CHECK: Type: SHT_PROGBITS
; CHECK: Flags [ (0x12)
; CHECK: SHF_ALLOC
; CHECK: SHF_MERGE
; CHECK: ]
; CHECK: Address: 0x0
; CHECK: Offset: 0x{{[1-9A-F][0-9A-F]*}}
; CHECK: Size: 8
; CHECK: Link: 0
; CHECK: Info: 0
; CHECK: AddressAlignment: 4
; CHECK: EntrySize: 4
; CHECK: SectionData (
; CHECK: 0000: A0709D3F 00000080
; CHECK: )
; CHECK: }
; CHECK: Section {
; CHECK: Index: {{[1-9][0-9]*}}
; CHECK: Name: .rodata.cst8
; CHECK: Type: SHT_PROGBITS
; CHECK: Flags [ (0x12)
; CHECK: SHF_ALLOC
; CHECK: SHF_MERGE
; CHECK: ]
; CHECK: Address: 0x0
; CHECK: Offset: 0x{{[1-9A-F][0-9A-F]*}}
; CHECK: Size: 24
; CHECK: Link: 0
; CHECK: Info: 0
; CHECK: AddressAlignment: 8
; CHECK: EntrySize: 8
; CHECK: SectionData (
; CHECK: 0000: 03000000 0000F8FF FFFFFFFF FFFFF7FF
; CHECK: 0010: FFFFFFFF FFFFFFFF
; CHECK: )
; CHECK: }
; CHECK: Section {
; CHECK: Index: {{[1-9][0-9]*}}
; CHECK: Name: .shstrtab
; CHECK: Type: SHT_STRTAB
; CHECK: Flags [ (0x0)
......@@ -203,6 +243,42 @@ define void @_start(i32) {
; CHECK-NEXT: }
; TODO: fill in the data symbols.
; CHECK: Symbol {
; CHECK: Name: .L$double$0
; CHECK-NEXT: Value: 0x10
; CHECK-NEXT: Size: 0
; CHECK-NEXT: Binding: Local (0x0)
; CHECK-NEXT: Type: None (0x0)
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .rodata.cst8
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: .L$double$2
; CHECK-NEXT: Value: 0x0
; CHECK-NEXT: Size: 0
; CHECK-NEXT: Binding: Local (0x0)
; CHECK-NEXT: Type: None (0x0)
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .rodata.cst8
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: .L$float$0
; CHECK-NEXT: Value: 0x4
; CHECK-NEXT: Size: 0
; CHECK-NEXT: Binding: Local (0x0)
; CHECK-NEXT: Type: None (0x0)
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .rodata.cst4
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: .L$float$1
; CHECK-NEXT: Value: 0x0
; CHECK-NEXT: Size: 0
; CHECK-NEXT: Binding: Local (0x0)
; CHECK-NEXT: Type: None (0x0)
; CHECK-NEXT: Other: 0
; CHECK-NEXT: Section: .rodata.cst4
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: returnDoubleConst
; CHECK-NEXT: Value: 0x{{[1-9A-F][0-9A-F]*}}
; CHECK-NEXT: Size: 0
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment