From d7879598acc930291b9c42b6a7e22b807a9c4921 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Thu, 18 Jul 2024 12:57:14 +1000 Subject: [PATCH] build/elf: optimise output of version definitions This handles the common case where there are only two version definitions which have the same name. When rewriting files, we are required to optimise at least as well as the original file so that it fits in the allocated space. --- crates/rewrite/testfiles/elf/libbase.so.noop | 1313 ++++++++++++++++++ crates/rewrite/tests/testfiles.rs | 19 + src/build/elf.rs | 33 +- src/write/elf/writer.rs | 32 +- testfiles | 2 +- 5 files changed, 1386 insertions(+), 13 deletions(-) create mode 100644 crates/rewrite/testfiles/elf/libbase.so.noop diff --git a/crates/rewrite/testfiles/elf/libbase.so.noop b/crates/rewrite/testfiles/elf/libbase.so.noop new file mode 100644 index 00000000..bf66c185 --- /dev/null +++ b/crates/rewrite/testfiles/elf/libbase.so.noop @@ -0,0 +1,1313 @@ +Format: ELF 64-bit +FileHeader { + Ident { + Magic: [7F, 45, 4C, 46] + Class: ELFCLASS64 (0x2) + Data: ELFDATA2LSB (0x1) + Version: EV_CURRENT (0x1) + OsAbi: ELFOSABI_SYSV (0x0) + AbiVersion: 0x0 + Unused: [0, 0, 0, 0, 0, 0, 0] + } + Type: ET_DYN (0x3) + Machine: EM_X86_64 (0x3E) + Version: EV_CURRENT (0x1) + Entry: 0x0 + ProgramHeaderOffset: 0x40 + SectionHeaderOffset: 0x3580 + Flags: 0x0 + HeaderSize: 0x40 + ProgramHeaderEntrySize: 0x38 + ProgramHeaderCount: 11 + SectionHeaderEntrySize: 0x40 + SectionHeaderCount: 31 + SectionHeaderStringTableIndex: 30 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x580 + MemorySize: 0x580 + Flags: 0x4 + PF_R (0x4) + Align: 0x1000 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x1000 + VirtualAddress: 0x1000 + PhysicalAddress: 0x1000 + FileSize: 0x149 + MemorySize: 0x149 + Flags: 0x5 + PF_X (0x1) + PF_R (0x4) + Align: 0x1000 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x2000 + VirtualAddress: 0x2000 + PhysicalAddress: 0x2000 + FileSize: 0xD4 + MemorySize: 0xD4 + Flags: 0x4 + PF_R (0x4) + Align: 0x1000 +} +ProgramHeader { + Type: PT_LOAD (0x1) + Offset: 0x2DF0 + VirtualAddress: 0x3DF0 + PhysicalAddress: 0x3DF0 + FileSize: 0x238 + MemorySize: 0x240 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x1000 +} +ProgramHeader { + Type: PT_DYNAMIC (0x2) + Offset: 0x2E00 + VirtualAddress: 0x3E00 + PhysicalAddress: 0x3E00 + FileSize: 0x1E0 + MemorySize: 0x1E0 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x8 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x1000 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x113C + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x3DF0 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x3DF8 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2F0 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x3D8 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x318 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x82 + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x4000 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x568 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x4C0 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xA8 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_VERDEF (0x6FFFFFFC) + Value: 0x470 + } + Dynamic { + Tag: DT_VERDEFNUM (0x6FFFFFFD) + Value: 0x2 + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x4A0 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x45A + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +ProgramHeader { + Type: PT_NOTE (0x4) + Offset: 0x2A8 + VirtualAddress: 0x2A8 + PhysicalAddress: 0x2A8 + FileSize: 0x20 + MemorySize: 0x20 + Flags: 0x4 + PF_R (0x4) + Align: 0x8 + Note { + Name: "GNU" + Type: NT_GNU_PROPERTY_TYPE_0 (0x5) + Property { + Type: GNU_PROPERTY_X86_FEATURE_1_AND (0xC0000002) + Value: 0x3 + GNU_PROPERTY_X86_FEATURE_1_IBT (0x1) + GNU_PROPERTY_X86_FEATURE_1_SHSTK (0x2) + } + } +} +ProgramHeader { + Type: PT_NOTE (0x4) + Offset: 0x2C8 + VirtualAddress: 0x2C8 + PhysicalAddress: 0x2C8 + FileSize: 0x24 + MemorySize: 0x24 + Flags: 0x4 + PF_R (0x4) + Align: 0x4 + Note { + Name: "GNU" + Type: NT_GNU_BUILD_ID (0x3) + Desc: [EB, 15, C, 53, 31, 21, FF, 59, D9, 7D, F1, 28, C1, C8, CF, 2A, 85, 82, CC, 91] + } +} +ProgramHeader { + Type: PT_GNU_PROPERTY (0x6474E553) + Offset: 0x2A8 + VirtualAddress: 0x2A8 + PhysicalAddress: 0x2A8 + FileSize: 0x20 + MemorySize: 0x20 + Flags: 0x4 + PF_R (0x4) + Align: 0x8 +} +ProgramHeader { + Type: PT_GNU_EH_FRAME (0x6474E550) + Offset: 0x2010 + VirtualAddress: 0x2010 + PhysicalAddress: 0x2010 + FileSize: 0x2C + MemorySize: 0x2C + Flags: 0x4 + PF_R (0x4) + Align: 0x4 +} +ProgramHeader { + Type: PT_GNU_STACK (0x6474E551) + Offset: 0x0 + VirtualAddress: 0x0 + PhysicalAddress: 0x0 + FileSize: 0x0 + MemorySize: 0x0 + Flags: 0x6 + PF_W (0x2) + PF_R (0x4) + Align: 0x10 +} +ProgramHeader { + Type: PT_GNU_RELRO (0x6474E552) + Offset: 0x2DF0 + VirtualAddress: 0x3DF0 + PhysicalAddress: 0x3DF0 + FileSize: 0x210 + MemorySize: 0x210 + Flags: 0x4 + PF_R (0x4) + Align: 0x1 +} +SectionHeader { + Index: 0 + Name: "" + Type: SHT_NULL (0x0) + Flags: 0x0 + Address: 0x0 + Offset: 0x0 + Size: 0x0 + Link: 0 + Info: 0 + AddressAlign: 0x0 + EntrySize: 0x0 +} +SectionHeader { + Index: 1 + Name: ".note.gnu.property" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2A8 + Offset: 0x2A8 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 + Note { + Name: "GNU" + Type: NT_GNU_PROPERTY_TYPE_0 (0x5) + Property { + Type: GNU_PROPERTY_X86_FEATURE_1_AND (0xC0000002) + Value: 0x3 + GNU_PROPERTY_X86_FEATURE_1_IBT (0x1) + GNU_PROPERTY_X86_FEATURE_1_SHSTK (0x2) + } + } +} +SectionHeader { + Index: 2 + Name: ".note.gnu.build-id" + Type: SHT_NOTE (0x7) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2C8 + Offset: 0x2C8 + Size: 0x24 + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 + Note { + Name: "GNU" + Type: NT_GNU_BUILD_ID (0x3) + Desc: [EB, 15, C, 53, 31, 21, FF, 59, D9, 7D, F1, 28, C1, C8, CF, 2A, 85, 82, CC, 91] + } +} +SectionHeader { + Index: 3 + Name: ".gnu.hash" + Type: SHT_GNU_HASH (0x6FFFFFF6) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2F0 + Offset: 0x2F0 + Size: 0x24 + Link: 4 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 + GnuHash { + BucketCount: 2 + SymbolBase: 7 + BloomCount: 1 + BloomShift: 6 + } +} +SectionHeader { + Index: 4 + Name: ".dynsym" + Type: SHT_DYNSYM (0xB) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x318 + Offset: 0x318 + Size: 0xC0 + Link: 5 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x18 + Symbol { + Index: 0 + Name: 0x0 + Version: VER_NDX_LOCAL (0x0) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 1 + Name: "_ITM_deregisterTMCloneTable" + Version: VER_NDX_GLOBAL (0x1) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 2 + Name: "printf" + Version: "GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 3 + Name: "__gmon_start__" + Version: VER_NDX_GLOBAL (0x1) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 4 + Name: "_ITM_registerTMCloneTable" + Version: VER_NDX_GLOBAL (0x1) + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 5 + Name: "__cxa_finalize" + Version: "GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 6 + Name: "libbase.so" + Version: "libbase.so" + Value: 0x0 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 7 + Name: "main" + Version: "libbase.so" + Value: 0x1119 + Size: 0x23 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } +} +SectionHeader { + Index: 5 + Name: ".dynstr" + Type: SHT_STRTAB (0x3) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x3D8 + Offset: 0x3D8 + Size: 0x82 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 6 + Name: ".gnu.version" + Type: SHT_GNU_VERSYM (0x6FFFFFFF) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x45A + Offset: 0x45A + Size: 0x10 + Link: 4 + Info: 0 + AddressAlign: 0x2 + EntrySize: 0x2 + VersionSymbol { + Index: 0 + Version: VER_NDX_LOCAL (0x0) + } + VersionSymbol { + Index: 1 + Version: VER_NDX_GLOBAL (0x1) + } + VersionSymbol { + Index: 2 + Version: "GLIBC_2.2.5" + } + VersionSymbol { + Index: 3 + Version: VER_NDX_GLOBAL (0x1) + } + VersionSymbol { + Index: 4 + Version: VER_NDX_GLOBAL (0x1) + } + VersionSymbol { + Index: 5 + Version: "GLIBC_2.2.5" + } + VersionSymbol { + Index: 6 + Version: "libbase.so" + } + VersionSymbol { + Index: 7 + Version: "libbase.so" + } +} +SectionHeader { + Index: 7 + Name: ".gnu.version_d" + Type: SHT_GNU_VERDEF (0x6FFFFFFD) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x470 + Offset: 0x470 + Size: 0x30 + Link: 5 + Info: 2 + AddressAlign: 0x8 + EntrySize: 0x0 + VersionDefinition { + Version: 1 + Flags: 0x1 + VER_FLG_BASE (0x1) + Index: 1 + AuxCount: 1 + Hash: 0x88E6A1F + AuxOffset: 40 + NextOffset: 20 + Aux { + Name: "libbase.so" + NextOffset: 0 + } + } + VersionDefinition { + Version: 1 + Flags: 0x0 + Index: 2 + AuxCount: 1 + Hash: 0x88E6A1F + AuxOffset: 20 + NextOffset: 0 + Aux { + Name: "libbase.so" + NextOffset: 0 + } + } +} +SectionHeader { + Index: 8 + Name: ".gnu.version_r" + Type: SHT_GNU_VERNEED (0x6FFFFFFE) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x4A0 + Offset: 0x4A0 + Size: 0x20 + Link: 5 + Info: 1 + AddressAlign: 0x8 + EntrySize: 0x0 + VersionNeed { + Version: 1 + AuxCount: 1 + Filename: "libc.so.6" + AuxOffset: 16 + NextOffset: 0 + Aux { + Hash: 0x9691A75 + Flags: 0x0 + Index: 3 + Name: "GLIBC_2.2.5" + NextOffset: 0 + } + } +} +SectionHeader { + Index: 9 + Name: ".rela.dyn" + Type: SHT_RELA (0x4) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x4C0 + Offset: 0x4C0 + Size: 0xA8 + Link: 4 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x18 + Relocation { + Offset: 0x3DF0 + Type: R_X86_64_RELATIVE (0x8) + Symbol: 0x0 + Addend: 0x1110 + } + Relocation { + Offset: 0x3DF8 + Type: R_X86_64_RELATIVE (0x8) + Symbol: 0x0 + Addend: 0x10D0 + } + Relocation { + Offset: 0x4020 + Type: R_X86_64_RELATIVE (0x8) + Symbol: 0x0 + Addend: 0x4020 + } + Relocation { + Offset: 0x3FE0 + Type: R_X86_64_GLOB_DAT (0x6) + Symbol: "_ITM_deregisterTMCloneTable" + } + Relocation { + Offset: 0x3FE8 + Type: R_X86_64_GLOB_DAT (0x6) + Symbol: "__gmon_start__" + } + Relocation { + Offset: 0x3FF0 + Type: R_X86_64_GLOB_DAT (0x6) + Symbol: "_ITM_registerTMCloneTable" + } + Relocation { + Offset: 0x3FF8 + Type: R_X86_64_GLOB_DAT (0x6) + Symbol: "__cxa_finalize" + } +} +SectionHeader { + Index: 10 + Name: ".rela.plt" + Type: SHT_RELA (0x4) + Flags: 0x42 + SHF_ALLOC (0x2) + SHF_INFO_LINK (0x40) + Address: 0x568 + Offset: 0x568 + Size: 0x18 + Link: 4 + Info: 24 + AddressAlign: 0x8 + EntrySize: 0x18 + Relocation { + Offset: 0x4018 + Type: R_X86_64_JUMP_SLOT (0x7) + Symbol: "printf" + } +} +SectionHeader { + Index: 11 + Name: ".init" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x1000 + Offset: 0x1000 + Size: 0x1B + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 12 + Name: ".plt" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x1020 + Offset: 0x1020 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x10 +} +SectionHeader { + Index: 13 + Name: ".plt.got" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x1040 + Offset: 0x1040 + Size: 0x10 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x10 +} +SectionHeader { + Index: 14 + Name: ".plt.sec" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x1050 + Offset: 0x1050 + Size: 0x10 + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x10 +} +SectionHeader { + Index: 15 + Name: ".text" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x1060 + Offset: 0x1060 + Size: 0xDC + Link: 0 + Info: 0 + AddressAlign: 0x10 + EntrySize: 0x0 +} +SectionHeader { + Index: 16 + Name: ".fini" + Type: SHT_PROGBITS (0x1) + Flags: 0x6 + SHF_ALLOC (0x2) + SHF_EXECINSTR (0x4) + Address: 0x113C + Offset: 0x113C + Size: 0xD + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 17 + Name: ".rodata" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2000 + Offset: 0x2000 + Size: 0xD + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 18 + Name: ".eh_frame_hdr" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2010 + Offset: 0x2010 + Size: 0x2C + Link: 0 + Info: 0 + AddressAlign: 0x4 + EntrySize: 0x0 +} +SectionHeader { + Index: 19 + Name: ".eh_frame" + Type: SHT_PROGBITS (0x1) + Flags: 0x2 + SHF_ALLOC (0x2) + Address: 0x2040 + Offset: 0x2040 + Size: 0x94 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 20 + Name: ".init_array" + Type: SHT_INIT_ARRAY (0xE) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x3DF0 + Offset: 0x2DF0 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 21 + Name: ".fini_array" + Type: SHT_FINI_ARRAY (0xF) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x3DF8 + Offset: 0x2DF8 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 22 + Name: ".dynamic" + Type: SHT_DYNAMIC (0x6) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x3E00 + Offset: 0x2E00 + Size: 0x1A0 + Link: 5 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x10 + Dynamic { + Tag: DT_NEEDED (0x1) + Value: "libc.so.6" + } + Dynamic { + Tag: DT_INIT (0xC) + Value: 0x1000 + } + Dynamic { + Tag: DT_FINI (0xD) + Value: 0x113C + } + Dynamic { + Tag: DT_INIT_ARRAY (0x19) + Value: 0x3DF0 + } + Dynamic { + Tag: DT_INIT_ARRAYSZ (0x1B) + Value: 0x8 + } + Dynamic { + Tag: DT_FINI_ARRAY (0x1A) + Value: 0x3DF8 + } + Dynamic { + Tag: DT_FINI_ARRAYSZ (0x1C) + Value: 0x8 + } + Dynamic { + Tag: DT_GNU_HASH (0x6FFFFEF5) + Value: 0x2F0 + } + Dynamic { + Tag: DT_STRTAB (0x5) + Value: 0x3D8 + } + Dynamic { + Tag: DT_SYMTAB (0x6) + Value: 0x318 + } + Dynamic { + Tag: DT_STRSZ (0xA) + Value: 0x82 + } + Dynamic { + Tag: DT_SYMENT (0xB) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTGOT (0x3) + Value: 0x4000 + } + Dynamic { + Tag: DT_PLTRELSZ (0x2) + Value: 0x18 + } + Dynamic { + Tag: DT_PLTREL (0x14) + Value: 0x7 + } + Dynamic { + Tag: DT_JMPREL (0x17) + Value: 0x568 + } + Dynamic { + Tag: DT_RELA (0x7) + Value: 0x4C0 + } + Dynamic { + Tag: DT_RELASZ (0x8) + Value: 0xA8 + } + Dynamic { + Tag: DT_RELAENT (0x9) + Value: 0x18 + } + Dynamic { + Tag: DT_VERDEF (0x6FFFFFFC) + Value: 0x470 + } + Dynamic { + Tag: DT_VERDEFNUM (0x6FFFFFFD) + Value: 0x2 + } + Dynamic { + Tag: DT_VERNEED (0x6FFFFFFE) + Value: 0x4A0 + } + Dynamic { + Tag: DT_VERNEEDNUM (0x6FFFFFFF) + Value: 0x1 + } + Dynamic { + Tag: DT_VERSYM (0x6FFFFFF0) + Value: 0x45A + } + Dynamic { + Tag: DT_RELACOUNT (0x6FFFFFF9) + Value: 0x3 + } + Dynamic { + Tag: DT_NULL (0x0) + Value: 0x0 + } +} +SectionHeader { + Index: 23 + Name: ".got" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x3FE0 + Offset: 0x2FE0 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 24 + Name: ".got.plt" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x4000 + Offset: 0x3000 + Size: 0x20 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x8 +} +SectionHeader { + Index: 25 + Name: ".data" + Type: SHT_PROGBITS (0x1) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x4020 + Offset: 0x3020 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x8 + EntrySize: 0x0 +} +SectionHeader { + Index: 26 + Name: ".bss" + Type: SHT_NOBITS (0x8) + Flags: 0x3 + SHF_WRITE (0x1) + SHF_ALLOC (0x2) + Address: 0x4028 + Offset: 0x3028 + Size: 0x8 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 27 + Name: ".comment" + Type: SHT_PROGBITS (0x1) + Flags: 0x30 + SHF_MERGE (0x10) + SHF_STRINGS (0x20) + Address: 0x0 + Offset: 0x3028 + Size: 0x2B + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x1 +} +SectionHeader { + Index: 28 + Name: ".symtab" + Type: SHT_SYMTAB (0x2) + Flags: 0x0 + Address: 0x0 + Offset: 0x3058 + Size: 0x288 + Link: 29 + Info: 20 + AddressAlign: 0x8 + EntrySize: 0x18 + Symbol { + Index: 0 + Name: 0x0 + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 1 + Name: "crtstuff.c" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 2 + Name: "deregister_tm_clones" + Value: 0x1060 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 3 + Name: "register_tm_clones" + Value: 0x1090 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 4 + Name: "__do_global_dtors_aux" + Value: 0x10D0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 5 + Name: "completed.0" + Value: 0x4028 + Size: 0x1 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 26 + } + Symbol { + Index: 6 + Name: "__do_global_dtors_aux_fini_array_entry" + Value: 0x3DF8 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 21 + } + Symbol { + Index: 7 + Name: "frame_dummy" + Value: 0x1110 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 8 + Name: "__frame_dummy_init_array_entry" + Value: 0x3DF0 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 20 + } + Symbol { + Index: 9 + Name: "base.c" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 10 + Name: "crtstuff.c" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 11 + Name: "__FRAME_END__" + Value: 0x20D0 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 19 + } + Symbol { + Index: 12 + Name: "" + Value: 0x0 + Size: 0x0 + Type: STT_FILE (0x4) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 13 + Name: "_fini" + Value: 0x113C + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 16 + } + Symbol { + Index: 14 + Name: "__dso_handle" + Value: 0x4020 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 25 + } + Symbol { + Index: 15 + Name: "_DYNAMIC" + Value: 0x3E00 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 22 + } + Symbol { + Index: 16 + Name: "__GNU_EH_FRAME_HDR" + Value: 0x2010 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 18 + } + Symbol { + Index: 17 + Name: "__TMC_END__" + Value: 0x4028 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 25 + } + Symbol { + Index: 18 + Name: "_GLOBAL_OFFSET_TABLE_" + Value: 0x4000 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 24 + } + Symbol { + Index: 19 + Name: "_init" + Value: 0x1000 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_LOCAL (0x0) + Other: STV_DEFAULT (0x0) + SectionIndex: 11 + } + Symbol { + Index: 20 + Name: "_ITM_deregisterTMCloneTable" + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 21 + Name: "printf@GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 22 + Name: "__gmon_start__" + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 23 + Name: "main" + Value: 0x1119 + Size: 0x23 + Type: STT_FUNC (0x2) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: 15 + } + Symbol { + Index: 24 + Name: "libbase.so" + Value: 0x0 + Size: 0x0 + Type: STT_OBJECT (0x1) + Bind: STB_GLOBAL (0x1) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_ABS (0xFFF1) + } + Symbol { + Index: 25 + Name: "_ITM_registerTMCloneTable" + Value: 0x0 + Size: 0x0 + Type: STT_NOTYPE (0x0) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } + Symbol { + Index: 26 + Name: "__cxa_finalize@GLIBC_2.2.5" + Value: 0x0 + Size: 0x0 + Type: STT_FUNC (0x2) + Bind: STB_WEAK (0x2) + Other: STV_DEFAULT (0x0) + SectionIndex: SHN_UNDEF (0x0) + } +} +SectionHeader { + Index: 29 + Name: ".strtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x32E0 + Size: 0x184 + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} +SectionHeader { + Index: 30 + Name: ".shstrtab" + Type: SHT_STRTAB (0x3) + Flags: 0x0 + Address: 0x0 + Offset: 0x3464 + Size: 0x11C + Link: 0 + Info: 0 + AddressAlign: 0x1 + EntrySize: 0x0 +} diff --git a/crates/rewrite/tests/testfiles.rs b/crates/rewrite/tests/testfiles.rs index 0f64dd8b..36ce3978 100644 --- a/crates/rewrite/tests/testfiles.rs +++ b/crates/rewrite/tests/testfiles.rs @@ -22,6 +22,25 @@ fn rewrite_base() { fail_message(fail); } +#[test] +fn rewrite_base_version() { + let print_options = readobj::PrintOptions { + string_indices: false, + ..readobj::PrintOptions::all() + }; + let mut fail = false; + + let options = object_rewrite::Options::default(); + fail |= testfile( + "elf/libbase.so", + "elf/libbase.so.noop", + options, + &print_options, + ); + + fail_message(fail); +} + #[test] fn rewrite_symbols() { let print_options = readobj::PrintOptions { diff --git a/src/build/elf.rs b/src/build/elf.rs index 6030a604..9e31778b 100644 --- a/src/build/elf.rs +++ b/src/build/elf.rs @@ -997,6 +997,7 @@ impl<'data> Builder<'data> { // Count the versions and add version strings. let mut verdef_count = 0; let mut verdaux_count = 0; + let mut verdef_shared_base = false; let mut verneed_count = 0; let mut vernaux_count = 0; let mut out_version_files = vec![VersionFileOut::default(); self.version_files.len()]; @@ -1008,11 +1009,15 @@ impl<'data> Builder<'data> { for version in &self.versions { match &version.data { VersionData::Def(def) => { - verdef_count += 1; - verdaux_count += def.names.len(); - for name in &def.names { - writer.add_dynamic_string(name); + if def.is_shared(verdef_count, self.version_base.as_ref()) { + verdef_shared_base = true; + } else { + verdaux_count += def.names.len(); + for name in &def.names { + writer.add_dynamic_string(name); + } } + verdef_count += 1; } VersionData::Need(need) => { vernaux_count += 1; @@ -1456,13 +1461,18 @@ impl<'data> Builder<'data> { SectionData::GnuVerdef => { writer.write_align_gnu_verdef(); if let Some(version_base) = &self.version_base { - writer.write_gnu_verdef(&write::elf::Verdef { + let verdef = write::elf::Verdef { version: elf::VER_DEF_CURRENT, flags: elf::VER_FLG_BASE, index: 1, aux_count: 1, name: writer.get_dynamic_string(version_base), - }); + }; + if verdef_shared_base { + writer.write_gnu_verdef_shared(&verdef); + } else { + writer.write_gnu_verdef(&verdef); + } } for version in &self.versions { if let VersionData::Def(def) = &version.data { @@ -1977,8 +1987,10 @@ impl<'data> Builder<'data> { } for version in &self.versions { if let VersionData::Def(def) = &version.data { + if !def.is_shared(verdef_count, self.version_base.as_ref()) { + verdaux_count += def.names.len(); + } verdef_count += 1; - verdaux_count += def.names.len(); } } self.class().gnu_verdef_size(verdef_count, verdaux_count) @@ -2992,6 +3004,13 @@ pub struct VersionDef<'data> { pub flags: u16, } +impl<'data> VersionDef<'data> { + /// Optimise for the common case where the first version is the same as the base version. + fn is_shared(&self, index: usize, base: Option<&ByteString<'_>>) -> bool { + index == 1 && self.names.len() == 1 && self.names.first() == base + } +} + /// A GNU version dependency. #[derive(Debug)] pub struct VersionNeed<'data> { diff --git a/src/write/elf/writer.rs b/src/write/elf/writer.rs index 420a9ea5..e862ee52 100644 --- a/src/write/elf/writer.rs +++ b/src/write/elf/writer.rs @@ -1629,12 +1629,9 @@ impl<'a> Writer<'a> { + verdef.aux_count as u32 * mem::size_of::>() as u32 }; + debug_assert_ne!(verdef.aux_count, 0); self.gnu_verdaux_remaining = verdef.aux_count; - let vd_aux = if verdef.aux_count == 0 { - 0 - } else { - mem::size_of::>() as u32 - }; + let vd_aux = mem::size_of::>() as u32; self.buffer.write(&elf::Verdef { vd_version: U16::new(self.endian, verdef.version), @@ -1648,6 +1645,31 @@ impl<'a> Writer<'a> { self.write_gnu_verdaux(verdef.name); } + /// Write a version definition entry that shares the names of the next definition. + /// + /// This is typically useful when there are only two versions (including the base) + /// and they have the same name. + pub fn write_gnu_verdef_shared(&mut self, verdef: &Verdef) { + debug_assert_ne!(self.gnu_verdef_remaining, 0); + self.gnu_verdef_remaining -= 1; + debug_assert_ne!(self.gnu_verdef_remaining, 0); + let vd_next = mem::size_of::>() as u32; + + debug_assert_ne!(verdef.aux_count, 0); + self.gnu_verdaux_remaining = 0; + let vd_aux = 2 * mem::size_of::>() as u32; + + self.buffer.write(&elf::Verdef { + vd_version: U16::new(self.endian, verdef.version), + vd_flags: U16::new(self.endian, verdef.flags), + vd_ndx: U16::new(self.endian, verdef.index), + vd_cnt: U16::new(self.endian, verdef.aux_count), + vd_hash: U32::new(self.endian, elf::hash(self.dynstr.get_string(verdef.name))), + vd_aux: U32::new(self.endian, vd_aux), + vd_next: U32::new(self.endian, vd_next), + }); + } + /// Write a version definition auxiliary entry. pub fn write_gnu_verdaux(&mut self, name: StringId) { debug_assert_ne!(self.gnu_verdaux_remaining, 0); diff --git a/testfiles b/testfiles index cebc8967..7651ef6c 160000 --- a/testfiles +++ b/testfiles @@ -1 +1 @@ -Subproject commit cebc89674360f005d415bae42ca66fa4bbfe40a5 +Subproject commit 7651ef6c5b5de609ddf0867eb781bec51a1631b9