Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -47,7 +47,8 @@ AssignmentKind, OutputSectionKind, InputSectionKind, - AssertKind + AssertKind, + BytesDataKind }; struct BaseCommand { @@ -138,6 +139,17 @@ Expr Expression; }; +struct BytesDataCommand : BaseCommand { + enum { Byte = 1, Short = 2, Long = 4, Quad = 8 }; + BytesDataCommand(unsigned Type, uint64_t Data) + : BaseCommand(BytesDataKind), Data(Data), Type(Type) {} + static bool classof(const BaseCommand *C); + unsigned getSize() { return (unsigned)Type; } + uint64_t Data; + unsigned Offset; + unsigned Type; +}; + struct PhdrsCommand { StringRef Name; unsigned Type; @@ -192,6 +204,7 @@ bool ignoreInterpSection(); ArrayRef getFiller(StringRef Name); + void writeDataBytes(StringRef Name, uint8_t *Buf); Expr getLma(StringRef Name); bool shouldKeep(InputSectionBase *S); void assignOffsets(OutputSectionCommand *Cmd); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -94,6 +94,10 @@ return C->Kind == AssertKind; } +bool BytesDataCommand::classof(const BaseCommand *C) { + return C->Kind == BytesDataKind; +} + template static bool isDiscarded(InputSectionBase *S) { return !S || !S->Live; } @@ -410,6 +414,13 @@ assignSectionSymbol(AssignCmd, CurOutSec, Dot - CurOutSec->getVA()); return; } + if (auto *DataCmd = dyn_cast(&Base)) { + DataCmd->Offset = Dot - CurOutSec->getVA(); + Dot += DataCmd->getSize(); + CurOutSec->setSize(Dot - CurOutSec->getVA()); + return; + } + auto &ICmd = cast(Base); for (InputSectionData *ID : ICmd.Sections) { auto *IB = static_cast *>(ID); @@ -639,6 +650,23 @@ return {}; } +template +void LinkerScript::writeDataBytes(StringRef Name, uint8_t *Buf) { + for (const std::unique_ptr &Base : Opt.Commands) { + if (auto *Cmd = dyn_cast(Base.get())) { + if (Cmd->Name == Name) { + for (const std::unique_ptr &Base2 : Cmd->Commands) + if (auto *DataCmd = dyn_cast(Base2.get())) + // Documentation says that if the object file format of the output + // file has an explicit endianness, the value will be stored in that + // endianness. + memcpy(Buf + DataCmd->Offset, &DataCmd->Data, DataCmd->getSize()); + return; + } + } + } +} + template Expr LinkerScript::getLma(StringRef Name) { for (const std::unique_ptr &Base : Opt.Commands) if (auto *Cmd = dyn_cast(Base.get())) @@ -761,6 +789,7 @@ void readVersionScriptCommand(); SymbolAssignment *readAssignment(StringRef Name); + BytesDataCommand *readBytesDataCommand(StringRef Tok); std::vector readFill(); OutputSectionCommand *readOutputSectionDescription(StringRef OutSec); std::vector readOutputSectionFiller(StringRef Tok); @@ -1207,6 +1236,8 @@ StringRef Tok = next(); if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok, false)) Cmd->Commands.emplace_back(Assignment); + else if (BytesDataCommand *Data = readBytesDataCommand(Tok)) + Cmd->Commands.emplace_back(Data); else if (Tok == "FILL") Cmd->Filler = readFill(); else if (Tok == "SORT") @@ -1396,6 +1427,25 @@ return true; } +BytesDataCommand *ScriptParser::readBytesDataCommand(StringRef Tok) { + unsigned Type = StringSwitch(Tok) + .Case("BYTE", BytesDataCommand::Byte) + .Case("SHORT", BytesDataCommand::Short) + .Case("LONG", BytesDataCommand::Long) + .Case("QUAD", BytesDataCommand::Quad) + .Default(-1); + if (Type == (unsigned)-1) + return nullptr; + + expect("("); + uint64_t Val = 0; + StringRef S = next(); + if (!readInteger(S, Val)) + setError("unexpected value: " + S); + expect(")"); + return new BytesDataCommand(Type, Val); +} + Expr ScriptParser::readPrimary() { if (peek() == "(") return readParenExpr(); Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -1005,6 +1005,7 @@ for (InputSection *C : Sections) C->writeTo(Buf); } + Script::X->writeDataBytes(this->Name, Buf); } template Index: test/ELF/linkerscript/data-commands.s =================================================================== --- test/ELF/linkerscript/data-commands.s +++ test/ELF/linkerscript/data-commands.s @@ -0,0 +1,34 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +# RUN: echo "SECTIONS \ +# RUN: { \ +# RUN: .foo : { \ +# RUN: *(.foo.1) \ +# RUN: BYTE(0x11) \ +# RUN: *(.foo.2) \ +# RUN: SHORT(0x1122) \ +# RUN: *(.foo.3) \ +# RUN: LONG(0x11223344) \ +# RUN: *(.foo.4) \ +# RUN: QUAD(0x1122334455667788) \ +# RUN: } \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-objdump -s %t | FileCheck %s + +# CHECK: Contents of section .foo: +# CHECK-NEXT: 00e8 ff11ff22 11ff4433 2211ff88 77665544 +# CHECK-NEXT: 00f8 332211 + +.section .foo.1, "a" + .byte 0xFF + +.section .foo.2, "a" + .byte 0xFF + +.section .foo.3, "a" + .byte 0xFF + +.section .foo.4, "a" + .byte 0xFF