Skip to content

[llvm-objcopy] Support CREL #97521

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 40 additions & 7 deletions llvm/lib/ObjCopy/ELF/ELFObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/MCELFExtras.h"
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/ELFObjectFile.h"
Expand Down Expand Up @@ -107,12 +108,29 @@ Error ELFSectionSizer<ELFT>::visit(SymbolTableSection &Sec) {
return Error::success();
}

template <bool Is64>
static SmallVector<char, 0> encodeCrel(ArrayRef<Relocation> Relocations) {
using uint = std::conditional_t<Is64, uint64_t, uint32_t>;
SmallVector<char, 0> Content;
raw_svector_ostream OS(Content);
ELF::encodeCrel<Is64>(OS, Relocations, [&](const Relocation &R) {
uint32_t CurSymIdx = R.RelocSymbol ? R.RelocSymbol->Index : 0;
return ELF::Elf_Crel<Is64>{static_cast<uint>(R.Offset), CurSymIdx, R.Type,
std::make_signed_t<uint>(R.Addend)};
});
return Content;
}

template <class ELFT>
Error ELFSectionSizer<ELFT>::visit(RelocationSection &Sec) {
Sec.EntrySize = Sec.Type == SHT_REL ? sizeof(Elf_Rel) : sizeof(Elf_Rela);
Sec.Size = Sec.Relocations.size() * Sec.EntrySize;
// Align to the largest field in Elf_Rel(a).
Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word);
if (Sec.Type == SHT_CREL) {
Sec.Size = encodeCrel<ELFT::Is64Bits>(Sec.Relocations).size();
} else {
Sec.EntrySize = Sec.Type == SHT_REL ? sizeof(Elf_Rel) : sizeof(Elf_Rela);
Sec.Size = Sec.Relocations.size() * Sec.EntrySize;
// Align to the largest field in Elf_Rel(a).
Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word);
}
return Error::success();
}

Expand Down Expand Up @@ -874,6 +892,8 @@ StringRef RelocationSectionBase::getNamePrefix() const {
return ".rel";
case SHT_RELA:
return ".rela";
case SHT_CREL:
return ".crel";
default:
llvm_unreachable("not a relocation section");
}
Expand Down Expand Up @@ -966,12 +986,16 @@ static void writeRel(const RelRange &Relocations, T *Buf, bool IsMips64EL) {
template <class ELFT>
Error ELFSectionWriter<ELFT>::visit(const RelocationSection &Sec) {
uint8_t *Buf = reinterpret_cast<uint8_t *>(Out.getBufferStart()) + Sec.Offset;
if (Sec.Type == SHT_REL)
if (Sec.Type == SHT_CREL) {
auto Content = encodeCrel<ELFT::Is64Bits>(Sec.Relocations);
memcpy(Buf, Content.data(), Content.size());
} else if (Sec.Type == SHT_REL) {
writeRel(Sec.Relocations, reinterpret_cast<Elf_Rel *>(Buf),
Sec.getObject().IsMips64EL);
else
} else {
writeRel(Sec.Relocations, reinterpret_cast<Elf_Rela *>(Buf),
Sec.getObject().IsMips64EL);
}
return Error::success();
}

Expand Down Expand Up @@ -1684,6 +1708,7 @@ Expected<SectionBase &> ELFBuilder<ELFT>::makeSection(const Elf_Shdr &Shdr) {
switch (Shdr.sh_type) {
case SHT_REL:
case SHT_RELA:
case SHT_CREL:
if (Shdr.sh_flags & SHF_ALLOC) {
if (Expected<ArrayRef<uint8_t>> Data = ElfFile.getSectionContents(Shdr))
return Obj.addSection<DynamicRelocationSection>(*Data);
Expand Down Expand Up @@ -1861,7 +1886,15 @@ template <class ELFT> Error ELFBuilder<ELFT>::readSections(bool EnsureSymtab) {

const typename ELFFile<ELFT>::Elf_Shdr *Shdr =
Sections->begin() + RelSec->Index;
if (RelSec->Type == SHT_REL) {
if (RelSec->Type == SHT_CREL) {
auto RelsOrRelas = ElfFile.crels(*Shdr);
if (!RelsOrRelas)
return RelsOrRelas.takeError();
if (Error Err = initRelocations(RelSec, RelsOrRelas->first))
return Err;
if (Error Err = initRelocations(RelSec, RelsOrRelas->second))
return Err;
} else if (RelSec->Type == SHT_REL) {
Expected<typename ELFFile<ELFT>::Elf_Rel_Range> Rels =
ElfFile.rels(*Shdr);
if (!Rels)
Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/ObjCopy/ELF/ELFObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -881,7 +881,8 @@ class RelocationSectionBase : public SectionBase {
StringRef getNamePrefix() const;

static bool classof(const SectionBase *S) {
return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA;
return is_contained({ELF::SHT_REL, ELF::SHT_RELA, ELF::SHT_CREL},
S->OriginalType);
}
};

Expand Down Expand Up @@ -925,7 +926,7 @@ class RelocationSection
static bool classof(const SectionBase *S) {
if (S->OriginalFlags & ELF::SHF_ALLOC)
return false;
return S->OriginalType == ELF::SHT_REL || S->OriginalType == ELF::SHT_RELA;
return RelocationSectionBase::classof(S);
}
};

Expand Down
140 changes: 140 additions & 0 deletions llvm/test/tools/llvm-objcopy/ELF/crel.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# RUN: yaml2obj %s -o %t
# RUN: llvm-objcopy --remove-section=.foo --strip-symbol=unused %t %t.out
# RUN: llvm-readelf -Sr %t.out | FileCheck %s

# CHECK: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
# CHECK-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0
# CHECK-NEXT: [ 1] .text PROGBITS 0000000000000000 {{.*}} 000008 00 A 0 0 0
# CHECK-NEXT: [ 2] .crel.text CREL 0000000000000000 {{.*}} 000022 00 5 1 0
# CHECK-NEXT: [ 3] nonalloc PROGBITS 0000000000000000 {{.*}} 000030 00 0 0 0
# CHECK-NEXT: [ 4] .crelnonalloc CREL 0000000000000000 {{.*}} 00000b 00 5 3 0

# CHECK: Relocation section '.crel.text' at offset {{.*}} contains 4 entries:
# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
# CHECK-NEXT: 0000000000000001 {{.*}} R_X86_64_32 0000000000000000 g1 + 1
# CHECK-NEXT: 0000000000000002 {{.*}} R_X86_64_64 0000000000000000 l1 + 2
# CHECK-NEXT: 0000000000000000 {{.*}} R_X86_64_32S 0000000000000000 g1 - 1
# CHECK-NEXT: 0000000000000004 {{.*}} R_X86_64_32S 0000000000000000 .text - 8000000000000000
# CHECK-EMPTY:
# CHECK-NEXT: Relocation section '.crelnonalloc' at offset {{.*}} contains 3 entries:
# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
# CHECK-NEXT: 0000000000000010 {{.*}} R_X86_64_64 0000000000000000 g1 + 1
# CHECK-NEXT: 0000000000000020 {{.*}} R_X86_64_64 0000000000000000 g2 + 2
# CHECK-NEXT: 0000000000000030 {{.*}} R_X86_64_64 0

--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_X86_64

Sections:
- Name: .foo
Type: SHT_PROGBITS
Flags: [SHF_ALLOC]
- Name: .text
Type: SHT_PROGBITS
Content: "0000000000000000"
Flags: [SHF_ALLOC]
- Name: .crel.text
Type: SHT_CREL
Info: .text
Link: .symtab
Relocations:
- Offset: 0x1
Symbol: g1
Type: R_X86_64_32
Addend: 1
- Offset: 0x2
Symbol: l1
Type: R_X86_64_64
Addend: 2
- Offset: 0x0
Symbol: g1
Type: R_X86_64_32S
Addend: 0xffffffffffffffff
- Offset: 0x4
Symbol: .text
Type: R_X86_64_32S
Addend: 0x8000000000000000
- Name: nonalloc
Type: SHT_PROGBITS
Size: 0x30
- Name: .crelnonalloc
Type: SHT_CREL
Info: nonalloc
Link: .symtab
Relocations:
- Offset: 0x10
Symbol: g1
Type: R_X86_64_64
Addend: 1
- Offset: 0x20
Symbol: g2
Type: R_X86_64_64
Addend: 2
- Offset: 0x30
Symbol: 0
Type: R_X86_64_64

Symbols:
- Name: unused
Section: .text
- Name: .text
Type: STT_SECTION
Section: .text
- Name: l1
- Name: g1
Section: .text
Value: 0x0
Size: 4
Binding: STB_GLOBAL
- Name: g2
Binding: STB_GLOBAL

# RUN: yaml2obj --docnum=2 %s -o %t.32
# RUN: llvm-objcopy %t.32 %t.32.out
# RUN: llvm-readobj -r %t.32.out | FileCheck %s --check-prefix=CHECK2

# CHECK2: Relocations [
# CHECK2-NEXT: Section (2) .crel.text {
# CHECK2-NEXT: 0x0 R_X86_64_32S g1 0xFFFFFFFF
# CHECK2-NEXT: 0x4 R_X86_64_32S .text 0x80000000
# CHECK2-NEXT: }
# CHECK2-NEXT: ]

--- !ELF
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_X86_64

Sections:
- Name: .text
Type: SHT_PROGBITS
Content: "0000000000000000"
Flags: [SHF_ALLOC]
- Name: .crel.text
Type: SHT_CREL
Info: .text
Link: .symtab
Relocations:
- Offset: 0x0
Symbol: g1
Type: R_X86_64_32S
Addend: 0xffffffff
- Offset: 0x4
Symbol: .text
Type: R_X86_64_32S
Addend: 0x80000000

Symbols:
- Name: .text
Type: STT_SECTION
Section: .text
- Name: g1
Section: .text
Size: 4
Binding: STB_GLOBAL
11 changes: 10 additions & 1 deletion llvm/test/tools/llvm-objcopy/ELF/reloc-error-remove-symtab.test
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
# RUN: cp %t %t3
# RUN: not llvm-strip --no-strip-all -R .symtab %t3 2>&1 >/dev/null | FileCheck %s --check-prefix=ERR2 -DINPUT=%t3

# RUN: yaml2obj -DTYPE=SHT_CREL %s -o %t.crel
# RUN: not llvm-objcopy -R .symtab %t.crel %t2.crel 2>&1 >/dev/null | FileCheck %s --check-prefix=ERR1 -DINPUT=%t.crel

!ELF
FileHeader:
Class: ELFCLASS64
Expand All @@ -17,7 +20,7 @@ Sections:
AddressAlign: 0x0000000000000010
Content: "0000000000000000"
- Name: .rel.text
Type: SHT_REL
Type: [[TYPE=SHT_REL]]
Link: .symtab
Info: .text
Relocations:
Expand All @@ -40,6 +43,12 @@ Symbols:
# RUN: llvm-strip --no-strip-all --allow-broken-links -R .symtab %t5
# RUN: llvm-readobj --sections %t5 | FileCheck %s --check-prefix=SECTIONS --implicit-check-not=.symtab

# RUN: llvm-objcopy --allow-broken-links -R .symtab %t.crel %t4.crel
# RUN: llvm-readobj --sections %t4.crel | FileCheck %s --check-prefix=SECTIONS --implicit-check-not=.symtab
# RUN: cp %t.crel %t5.crel
# RUN: llvm-strip --no-strip-all --allow-broken-links -R .symtab %t5.crel
# RUN: llvm-readobj --sections %t5.crel | FileCheck %s --check-prefix=SECTIONS --implicit-check-not=.symtab

# SECTIONS: Name: .rel.text
# SECTIONS: Link
# SECTIONS-SAME: : 0
4 changes: 3 additions & 1 deletion llvm/test/tools/llvm-objcopy/ELF/strip-reloc-symbol.test
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# RUN: yaml2obj %s -o %t
# RUN: not llvm-objcopy -N foo %t %t2 2>&1 | FileCheck %s -DFILE=%t
# RUN: yaml2obj -DTYPE=SHT_CREL %s -o %t1
# RUN: not llvm-objcopy -N foo %t1 /dev/null 2>&1 | FileCheck %s -DFILE=%t1

!ELF
FileHeader:
Expand All @@ -15,7 +17,7 @@ Sections:
AddressAlign: 0x0000000000000010
Size: 64
- Name: .rel.text
Type: SHT_REL
Type: [[TYPE=SHT_REL]]
Info: .text
Relocations:
- Offset: 0x1000
Expand Down
Loading