mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 12:43:36 +01:00
[llvm-objcopy] Handle -O <format> flag.
Summary: The -O flag is currently being mostly ignored; it's only checked whether or not the output format is "binary". This adds support for a few formats (e.g. elf64-x86-64), so that when specified, the output can change between 32/64 bit and sizes/alignments are updated accordingly. This fixes PR39135 Reviewers: jakehehrlich, jhenderson, alexshap, espindola Reviewed By: jhenderson Subscribers: emaste, arichardson, llvm-commits Differential Revision: https://reviews.llvm.org/D53667 llvm-svn: 350541
This commit is contained in:
parent
7b9799ff50
commit
1f49e1569f
13
test/tools/llvm-objcopy/ELF/bad-output-format.test
Normal file
13
test/tools/llvm-objcopy/ELF/bad-output-format.test
Normal file
@ -0,0 +1,13 @@
|
||||
# RUN: yaml2obj %s > %t.o
|
||||
|
||||
# RUN: not llvm-objcopy -O xyz %t.o %t.2.o 2>&1 \
|
||||
# RUN: | FileCheck %s --check-prefix=BAD-OUTPUT-FORMAT
|
||||
|
||||
!ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS32
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_EXEC
|
||||
Machine: EM_386
|
||||
|
||||
# BAD-OUTPUT-FORMAT: Invalid output format: 'xyz'.
|
20
test/tools/llvm-objcopy/ELF/binary-input-with-arch.test
Normal file
20
test/tools/llvm-objcopy/ELF/binary-input-with-arch.test
Normal file
@ -0,0 +1,20 @@
|
||||
# RUN: echo -n abcd > %t.x-txt
|
||||
# Preserve input to verify it is not modified.
|
||||
# RUN: cp %t.x-txt %t-copy.txt
|
||||
# RUN: llvm-objcopy -I binary -B i386 -O elf64-x86-64 %t.x-txt %t.o
|
||||
# RUN: llvm-readobj --file-headers %t.o | FileCheck %s
|
||||
# RUN: cmp %t.x-txt %t-copy.txt
|
||||
|
||||
# Many uses of objcopy use no spaces in the flags, make sure that also works.
|
||||
# RUN: llvm-objcopy -Ibinary -Bi386 -Oelf64-x86-64 %t.x-txt %t-no-spaces.o
|
||||
# RUN: cmp %t.o %t-no-spaces.o
|
||||
|
||||
# CHECK: Format: ELF64-x86-64
|
||||
# CHECK-NEXT: Arch: x86_64
|
||||
# CHECK-NEXT: AddressSize: 64bit
|
||||
|
||||
# CHECK: Class: 64-bit
|
||||
# CHECK: DataEncoding: LittleEndian
|
||||
# CHECK: Machine: EM_X86_64
|
||||
# CHECK: HeaderSize: 64
|
||||
# CHECK: SectionHeaderEntrySize: 64
|
71
test/tools/llvm-objcopy/ELF/cross-arch-headers.test
Normal file
71
test/tools/llvm-objcopy/ELF/cross-arch-headers.test
Normal file
@ -0,0 +1,71 @@
|
||||
# RUN: yaml2obj %s > %t.o
|
||||
|
||||
# RUN: llvm-objcopy %t.o -O elf32-i386 %t.elf32_i386.o
|
||||
# RUN: llvm-readobj --file-headers %t.elf32_i386.o | FileCheck %s --check-prefixes=CHECK,I386,32
|
||||
|
||||
# RUN: llvm-objcopy %t.o -O elf32-powerpcle %t.elf32_ppcle.o
|
||||
# RUN: llvm-readobj --file-headers %t.elf32_ppcle.o | FileCheck %s --check-prefixes=CHECK,PPC,32
|
||||
|
||||
# RUN: llvm-objcopy %t.o -O elf32-x86-64 %t.elf32_x86_64.o
|
||||
# RUN: llvm-readobj --file-headers %t.elf32_x86_64.o | FileCheck %s --check-prefixes=CHECK,X86-64,32
|
||||
|
||||
# RUN: llvm-objcopy %t.o -O elf64-powerpcle %t.elf64_ppcle.o
|
||||
# RUN: llvm-readobj --file-headers %t.elf64_ppcle.o | FileCheck %s --check-prefixes=CHECK,PPC64,64
|
||||
|
||||
# RUN: llvm-objcopy %t.o -O elf64-x86-64 %t.elf64_x86_64.o
|
||||
# RUN: llvm-readobj --file-headers %t.elf64_x86_64.o | FileCheck %s --check-prefixes=CHECK,X86-64,64
|
||||
|
||||
!ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS32
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_EXEC
|
||||
Machine: EM_386
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
- Name: .data
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Symbols:
|
||||
Global:
|
||||
- Name: foo
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Value: 0x1234
|
||||
- Name: bar
|
||||
Type: STT_OBJECT
|
||||
Section: .data
|
||||
Value: 0xabcd
|
||||
|
||||
# CHECK: Format:
|
||||
# 32-SAME: ELF32-
|
||||
# 64-SAME: ELF64-
|
||||
# I386-SAME: i386
|
||||
# PPC-SAME: ppc
|
||||
# PPC64-SAME: ppc64
|
||||
# X86-64-SAME: x86-64
|
||||
|
||||
# I386-NEXT: Arch: i386
|
||||
# PPC-NEXT: Arch: powerpc
|
||||
# PPC64-NEXT: Arch: powerpc64le
|
||||
# X86-64-NEXT: Arch: x86_64
|
||||
|
||||
# 32-NEXT: AddressSize: 32bit
|
||||
# 64-NEXT: AddressSize: 64bit
|
||||
|
||||
# 32: Class: 32-bit
|
||||
# 64: Class: 64-bit
|
||||
# CHECK: DataEncoding: LittleEndian
|
||||
|
||||
# I386: Machine: EM_386
|
||||
# PPC: Machine: EM_PPC
|
||||
# PPC64: Machine: EM_PPC64
|
||||
# X86-64: Machine: EM_X86_64
|
||||
|
||||
# 32: HeaderSize: 52
|
||||
# 64: HeaderSize: 64
|
||||
|
||||
# 32: SectionHeaderEntrySize: 40
|
||||
# 64: SectionHeaderEntrySize: 64
|
153
test/tools/llvm-objcopy/ELF/cross-arch-sections-symbols.test
Normal file
153
test/tools/llvm-objcopy/ELF/cross-arch-sections-symbols.test
Normal file
@ -0,0 +1,153 @@
|
||||
# RUN: yaml2obj %s > %t.o
|
||||
# Preserve input to verify it is not modified.
|
||||
# RUN: cp %t.o %t-copy.o
|
||||
# RUN: llvm-objcopy %t.o -O elf64-x86-64 %t.2.o
|
||||
# RUN: llvm-readobj --sections --symbols %t.2.o | FileCheck %s
|
||||
# RUN: cmp %t.o %t-copy.o
|
||||
|
||||
!ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS32
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_EXEC
|
||||
Machine: EM_386
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
Size: 32
|
||||
- Name: .data
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Content: DEADBEEF
|
||||
Size: 16
|
||||
Symbols:
|
||||
Global:
|
||||
- Name: foo
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Value: 16
|
||||
Size: 8
|
||||
- Name: bar
|
||||
Type: STT_OBJECT
|
||||
Section: .data
|
||||
Size: 16
|
||||
|
||||
# CHECK: Sections [
|
||||
# CHECK-NEXT: Section {
|
||||
# CHECK-NEXT: Index: 0
|
||||
# CHECK-NEXT: Name: (0)
|
||||
# CHECK-NEXT: Type: SHT_NULL (0x0)
|
||||
# CHECK-NEXT: Flags [ (0x0)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Size: 0
|
||||
# CHECK-NEXT: Link: 0
|
||||
# CHECK-NEXT: Info: 0
|
||||
# CHECK-NEXT: AddressAlignment: 0
|
||||
# CHECK-NEXT: EntrySize: 0
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Section {
|
||||
# CHECK-NEXT: Index: 1
|
||||
# CHECK-NEXT: Name: .text
|
||||
# CHECK-NEXT: Type: SHT_PROGBITS (0x1)
|
||||
# CHECK-NEXT: Flags [ (0x6)
|
||||
# CHECK-NEXT: SHF_ALLOC (0x2)
|
||||
# CHECK-NEXT: SHF_EXECINSTR (0x4)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Size: 32
|
||||
# CHECK-NEXT: Link: 0
|
||||
# CHECK-NEXT: Info: 0
|
||||
# CHECK-NEXT: AddressAlignment: 0
|
||||
# CHECK-NEXT: EntrySize: 0
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Section {
|
||||
# CHECK-NEXT: Index: 2
|
||||
# CHECK-NEXT: Name: .data
|
||||
# CHECK-NEXT: Type: SHT_PROGBITS (0x1)
|
||||
# CHECK-NEXT: Flags [ (0x2)
|
||||
# CHECK-NEXT: SHF_ALLOC (0x2)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Size: 16
|
||||
# CHECK-NEXT: Link: 0
|
||||
# CHECK-NEXT: Info: 0
|
||||
# CHECK-NEXT: AddressAlignment: 0
|
||||
# CHECK-NEXT: EntrySize: 0
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Section {
|
||||
# CHECK-NEXT: Index: 3
|
||||
# CHECK-NEXT: Name: .symtab
|
||||
# CHECK-NEXT: Type: SHT_SYMTAB (0x2)
|
||||
# CHECK-NEXT: Flags [ (0x0)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Size: 72
|
||||
# CHECK-NEXT: Link: 4
|
||||
# CHECK-NEXT: Info: 1
|
||||
# CHECK-NEXT: AddressAlignment: 8
|
||||
# CHECK-NEXT: EntrySize: 24
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Section {
|
||||
# CHECK-NEXT: Index: 4
|
||||
# CHECK-NEXT: Name: .strtab
|
||||
# CHECK-NEXT: Type: SHT_STRTAB (0x3)
|
||||
# CHECK-NEXT: Flags [ (0x0)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Size: 10
|
||||
# CHECK-NEXT: Link: 0
|
||||
# CHECK-NEXT: Info: 0
|
||||
# CHECK-NEXT: AddressAlignment: 1
|
||||
# CHECK-NEXT: EntrySize: 0
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Section {
|
||||
# CHECK-NEXT: Index: 5
|
||||
# CHECK-NEXT: Name: .shstrtab
|
||||
# CHECK-NEXT: Type: SHT_STRTAB (0x3)
|
||||
# CHECK-NEXT: Flags [ (0x0)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Size: 39
|
||||
# CHECK-NEXT: Link: 0
|
||||
# CHECK-NEXT: Info: 0
|
||||
# CHECK-NEXT: AddressAlignment: 1
|
||||
# CHECK-NEXT: EntrySize: 0
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Symbols [
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name:
|
||||
# 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: Undefined
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name: foo
|
||||
# CHECK-NEXT: Value: 0x10
|
||||
# CHECK-NEXT: Size: 8
|
||||
# CHECK-NEXT: Binding: Global (0x1)
|
||||
# CHECK-NEXT: Type: Function (0x2)
|
||||
# CHECK-NEXT: Other: 0
|
||||
# CHECK-NEXT: Section: .text
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name: bar
|
||||
# CHECK-NEXT: Value: 0x0
|
||||
# CHECK-NEXT: Size: 16
|
||||
# CHECK-NEXT: Binding: Global (0x1)
|
||||
# CHECK-NEXT: Type: Object (0x1)
|
||||
# CHECK-NEXT: Other: 0
|
||||
# CHECK-NEXT: Section: .data
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
@ -189,6 +189,22 @@ static const MachineInfo &getMachineInfo(StringRef Arch) {
|
||||
return Iter->getValue();
|
||||
}
|
||||
|
||||
static const StringMap<MachineInfo> OutputFormatMap{
|
||||
// Name, {EMachine, 64bit, LittleEndian}
|
||||
{"elf32-i386", {ELF::EM_386, false, true}},
|
||||
{"elf32-powerpcle", {ELF::EM_PPC, false, true}},
|
||||
{"elf32-x86-64", {ELF::EM_X86_64, false, true}},
|
||||
{"elf64-powerpcle", {ELF::EM_PPC64, true, true}},
|
||||
{"elf64-x86-64", {ELF::EM_X86_64, true, true}},
|
||||
};
|
||||
|
||||
static const MachineInfo &getOutputFormatMachineInfo(StringRef Format) {
|
||||
auto Iter = OutputFormatMap.find(Format);
|
||||
if (Iter == std::end(OutputFormatMap))
|
||||
error("Invalid output format: '" + Format + "'");
|
||||
return Iter->getValue();
|
||||
}
|
||||
|
||||
static void addGlobalSymbolsFromFile(std::vector<std::string> &Symbols,
|
||||
StringRef Filename) {
|
||||
SmallVector<StringRef, 16> Lines;
|
||||
@ -266,6 +282,8 @@ DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
|
||||
error("Specified binary input without specifiying an architecture");
|
||||
Config.BinaryArch = getMachineInfo(BinaryArch);
|
||||
}
|
||||
if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary")
|
||||
Config.OutputArch = getOutputFormatMachineInfo(Config.OutputFormat);
|
||||
|
||||
if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
|
||||
OBJCOPY_compress_debug_sections_eq)) {
|
||||
|
@ -46,8 +46,10 @@ struct CopyConfig {
|
||||
StringRef OutputFilename;
|
||||
StringRef OutputFormat;
|
||||
|
||||
// Only applicable for --input-format=Binary
|
||||
// Only applicable for --input-format=binary
|
||||
MachineInfo BinaryArch;
|
||||
// Only applicable when --output-format!=binary (e.g. elf64-x86-64).
|
||||
Optional<MachineInfo> OutputArch;
|
||||
|
||||
// Advanced options
|
||||
StringRef AddGnuDebugLink;
|
||||
|
@ -173,6 +173,8 @@ static void splitDWOToFile(const CopyConfig &Config, const Reader &Reader,
|
||||
auto DWOFile = Reader.create();
|
||||
DWOFile->removeSections(
|
||||
[&](const SectionBase &Sec) { return onlyKeepDWOPred(*DWOFile, Sec); });
|
||||
if (Config.OutputArch)
|
||||
DWOFile->Machine = Config.OutputArch.getValue().EMachine;
|
||||
FileBuffer FB(File);
|
||||
auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType);
|
||||
Writer->finalize();
|
||||
@ -261,6 +263,8 @@ static void handleArgs(const CopyConfig &Config, Object &Obj,
|
||||
if (!Config.SplitDWO.empty()) {
|
||||
splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType);
|
||||
}
|
||||
if (Config.OutputArch)
|
||||
Obj.Machine = Config.OutputArch.getValue().EMachine;
|
||||
|
||||
// TODO: update or remove symbols only if there is an option that affects
|
||||
// them.
|
||||
@ -528,7 +532,10 @@ void executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
|
||||
BinaryReader Reader(Config.BinaryArch, &In);
|
||||
std::unique_ptr<Object> Obj = Reader.create();
|
||||
|
||||
const ElfType OutputElfType = getOutputElfType(Config.BinaryArch);
|
||||
// Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch
|
||||
// (-B<arch>).
|
||||
const ElfType OutputElfType = getOutputElfType(
|
||||
Config.OutputArch ? Config.OutputArch.getValue() : Config.BinaryArch);
|
||||
handleArgs(Config, *Obj, Reader, OutputElfType);
|
||||
std::unique_ptr<Writer> Writer =
|
||||
createWriter(Config, *Obj, Out, OutputElfType);
|
||||
@ -540,7 +547,10 @@ void executeObjcopyOnBinary(const CopyConfig &Config,
|
||||
object::ELFObjectFileBase &In, Buffer &Out) {
|
||||
ELFReader Reader(&In);
|
||||
std::unique_ptr<Object> Obj = Reader.create();
|
||||
const ElfType OutputElfType = getOutputElfType(In);
|
||||
// Prefer OutputArch (-O<format>) if set, otherwise infer it from the input.
|
||||
const ElfType OutputElfType =
|
||||
Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue())
|
||||
: getOutputElfType(In);
|
||||
ArrayRef<uint8_t> BuildIdBytes;
|
||||
|
||||
if (!Config.BuildIdLinkDir.empty()) {
|
||||
|
Loading…
Reference in New Issue
Block a user