From 7ffcc0a5e7eef51a2b869876d27abbb1aeed1e71 Mon Sep 17 00:00:00 2001 From: John Reiser Date: Wed, 27 May 2009 10:19:50 -0700 Subject: [PATCH] powerpc-darwin.dylib --- src/conf.h | 1 + src/p_mach.cpp | 59 +++++- src/p_mach.h | 39 ++++ src/p_mach_enum.h | 1 + src/packmast.cpp | 2 + src/stub/Makefile | 14 ++ src/stub/src/powerpc-darwin.dylib-entry.S | 185 ++++++++++++++++++ .../tmp/powerpc-darwin.dylib-entry.bin.dump | 52 +++++ 8 files changed, 349 insertions(+), 4 deletions(-) create mode 100644 src/stub/src/powerpc-darwin.dylib-entry.S create mode 100644 src/stub/tmp/powerpc-darwin.dylib-entry.bin.dump diff --git a/src/conf.h b/src/conf.h index 2b198440..78098cc1 100644 --- a/src/conf.h +++ b/src/conf.h @@ -475,6 +475,7 @@ private: #define UPX_F_MACH_ARMEL 32 #define UPX_F_DYLIB_i386 33 +#define UPX_F_DYLIB_PPC32 34 #define UPX_F_PLAIN_TEXT 127 diff --git a/src/p_mach.cpp b/src/p_mach.cpp index 52f7a78c..d6588618 100644 --- a/src/p_mach.cpp +++ b/src/p_mach.cpp @@ -63,6 +63,9 @@ static const // The runtime stub for the dyld -init routine does not use "fold"ed code. //#include "stub/i386-darwin.dylib-fold.h" +static const +#include "stub/powerpc-darwin.dylib-entry.h" + template PackMachBase::PackMachBase(InputFile *f, unsigned cputype, unsigned filetype, unsigned flavor, unsigned count, unsigned size) : @@ -87,6 +90,11 @@ PackDylibI386::PackDylibI386(InputFile *f) : super(f) my_filetype = Mach_header::MH_DYLIB; } +PackDylibPPC32::PackDylibPPC32(InputFile *f) : super(f) +{ + my_filetype = Mach_header::MH_DYLIB; +} + template const int *PackMachBase::getCompressionMethods(int method, int level) const { @@ -313,6 +321,14 @@ PackDylibI386::buildLoader(const Filter *ft) 0, 0, ft ); } +void +PackDylibPPC32::buildLoader(const Filter *ft) +{ + buildMachLoader( + stub_powerpc_darwin_dylib_entry, sizeof(stub_powerpc_darwin_dylib_entry), + 0, 0, ft ); +} + template void PackMachBase::patchLoader() { } @@ -430,6 +446,13 @@ void PackMachBase::pack4dylib( // append PackHeader case Mach_segment_command::LC_REEXPORT_DYLIB: hdrpos += seg->cmdsize; break; // contain no file offset fields + case Mach_segment_command::LC_TWOLEVEL_HINTS: { + Mach_twolevel_hints_command cmd = *(Mach_twolevel_hints_command const *)seg; + if (o_end_txt <= cmd.offset) { cmd.offset += slide; } + fo->seek(hdrpos, SEEK_SET); + fo->rewrite(&cmd, sizeof(cmd)); + hdrpos += sizeof(cmd); + } break; case Mach_segment_command::LC_ROUTINES_64: case Mach_segment_command::LC_ROUTINES: { Mach_routines_command cmd = *(Mach_routines_command const *)seg; @@ -527,9 +550,14 @@ void PackDylibI386::pack4(OutputFile *fo, Filter &ft) // append PackHeader pack4dylib(fo, ft, threado.state.eip); } +void PackDylibPPC32::pack4(OutputFile *fo, Filter &ft) // append PackHeader +{ + pack4dylib(fo, ft, threado.state.srr0); +} + void PackMachPPC32::pack3(OutputFile *fo, Filter &ft) // append loader { - BE32 disp; + TE32 disp; unsigned const zero = 0; unsigned len = fo->getBytesWritten(); fo->write(&zero, 3& (0u-len)); @@ -543,7 +571,7 @@ void PackMachPPC32::pack3(OutputFile *fo, Filter &ft) // append loader void PackMachI386::pack3(OutputFile *fo, Filter &ft) // append loader { - LE32 disp; + TE32 disp; unsigned const zero = 0; unsigned len = fo->getBytesWritten(); fo->write(&zero, 3& (0u-len)); @@ -557,7 +585,7 @@ void PackMachI386::pack3(OutputFile *fo, Filter &ft) // append loader void PackMachARMEL::pack3(OutputFile *fo, Filter &ft) // append loader { - LE32 disp; + TE32 disp; unsigned const zero = 0; unsigned len = fo->getBytesWritten(); fo->write(&zero, 3& (0u-len)); @@ -571,7 +599,30 @@ void PackMachARMEL::pack3(OutputFile *fo, Filter &ft) // append loader void PackDylibI386::pack3(OutputFile *fo, Filter &ft) // append loader { - LE32 disp; + TE32 disp; + unsigned const zero = 0; + unsigned len = fo->getBytesWritten(); + fo->write(&zero, 3& (0u-len)); + len += (3& (0u-len)) + 4*sizeof(disp); + + disp = prev_init_address; + fo->write(&disp, sizeof(disp)); // user .init_address + + disp = sizeof(mhdro) + mhdro.sizeofcmds + sizeof(l_info) + sizeof(p_info); + fo->write(&disp, sizeof(disp)); // src offset(compressed __TEXT) + + disp = len - disp - 3*sizeof(disp); + fo->write(&disp, sizeof(disp)); // length(compressed __TEXT) + + unsigned const save_sz_mach_headers(sz_mach_headers); + sz_mach_headers = 0; + super::pack3(fo, ft); + sz_mach_headers = save_sz_mach_headers; +} + +void PackDylibPPC32::pack3(OutputFile *fo, Filter &ft) // append loader +{ + TE32 disp; unsigned const zero = 0; unsigned len = fo->getBytesWritten(); fo->write(&zero, 3& (0u-len)); diff --git a/src/p_mach.h b/src/p_mach.h index 6158facf..f7e304be 100644 --- a/src/p_mach.h +++ b/src/p_mach.h @@ -210,6 +210,20 @@ __packed_struct(Mach_routines_command) #include "p_mach_enum.h" __packed_struct_end() +template +__packed_struct(Mach_twolevel_hints_command) + typedef typename TMachITypes::Word Word; + typedef typename TMachITypes::Addr Addr; + typedef typename TMachITypes::Off Off; + + Word cmd; + Word cmdsize; + Off offset; /* offset to the hint table */ + Word nhints; /* number of hints */ +#define WANT_MACH_SEGMENT_ENUM 1 +#include "p_mach_enum.h" +__packed_struct_end() + template __packed_struct(Mach_ppc_thread_state) typedef typename TMachITypes::Addr Addr; @@ -340,6 +354,7 @@ struct MachClass_32 typedef N_Mach::Mach_dysymtab_command Mach_dysymtab_command; typedef N_Mach::Mach_segsplit_info_command Mach_segsplit_info_command; typedef N_Mach::Mach_routines_command Mach_routines_command; + typedef N_Mach::Mach_twolevel_hints_command Mach_twolevel_hints_command; typedef N_Mach::Mach_ppc_thread_state Mach_ppc_thread_state; typedef N_Mach::Mach_i386_thread_state Mach_i386_thread_state; typedef N_Mach::Mach_ARM_thread_state Mach_ARM_thread_state; @@ -369,6 +384,7 @@ struct MachClass_64 typedef N_Mach::Mach_dysymtab_command Mach_dysymtab_command; typedef N_Mach::Mach_segsplit_info_command Mach_segsplit_info_command; typedef N_Mach::Mach_routines_command Mach_routines_command; + typedef N_Mach::Mach_twolevel_hints_command Mach_twolevel_hints_command; static void compileTimeAssertions() { BeLePolicy::compileTimeAssertions(); @@ -391,6 +407,7 @@ typedef MachClass_Host32::Mach_symtab_command Mach32_symtab_command; typedef MachClass_Host32::Mach_dysymtab_command Mach32_dysymtab_command; typedef MachClass_Host32::Mach_segsplit_info_command Mach32_segsplit_info_command; typedef MachClass_Host32::Mach_routines_command Mach32_routines_command; +typedef MachClass_Host32::Mach_twolevel_hints_command Mach32_twolevel_hints_command; typedef MachClass_Host64::Mach_segment_command Mach64_segment_command; typedef MachClass_Host64::Mach_section_command Mach64_section_command; @@ -398,6 +415,7 @@ typedef MachClass_Host64::Mach_symtab_command Mach64_symtab_command; typedef MachClass_Host64::Mach_dysymtab_command Mach64_dysymtab_command; typedef MachClass_Host64::Mach_segsplit_info_command Mach64_segsplit_info_command; typedef MachClass_Host64::Mach_routines_command Mach64_routines_command; +typedef MachClass_Host64::Mach_twolevel_hints_command Mach64_twolevel_hints_command; typedef MachClass_BE32::Mach_segment_command MachBE32_segment_command; typedef MachClass_BE32::Mach_section_command MachBE32_section_command; @@ -405,6 +423,7 @@ typedef MachClass_BE32::Mach_symtab_command MachBE32_symtab_command; typedef MachClass_BE32::Mach_dysymtab_command MachBE32_dysymtab_command; typedef MachClass_BE32::Mach_segsplit_info_command MachBE32_segsplit_info_command; typedef MachClass_BE32::Mach_routines_command MachBE32_routines_command; +typedef MachClass_BE32::Mach_twolevel_hints_command MachBE32_twolevel_hints_command; typedef MachClass_BE64::Mach_segment_command MachBE64_segment_command; typedef MachClass_BE64::Mach_section_command MachBE64_section_command; @@ -412,6 +431,7 @@ typedef MachClass_BE64::Mach_symtab_command MachBE64_symtab_command; typedef MachClass_BE64::Mach_dysymtab_command MachBE64_dysymtab_command; typedef MachClass_BE64::Mach_segsplit_info_command MachBE64_segsplit_info_command; typedef MachClass_BE64::Mach_routines_command MachBE64_routines_command; +typedef MachClass_BE64::Mach_twolevel_hints_command MachBE64_twolevel_hints_command; typedef MachClass_LE32::Mach_segment_command MachLE32_segment_command; typedef MachClass_LE32::Mach_section_command MachLE32_section_command; @@ -419,6 +439,7 @@ typedef MachClass_LE32::Mach_symtab_command MachLE32_symtab_command; typedef MachClass_LE32::Mach_dysymtab_command MachLE32_dysymtab_command; typedef MachClass_LE32::Mach_segsplit_info_command MachLE32_segsplit_info_command; typedef MachClass_LE32::Mach_routines_command MachLE32_routines_command; +typedef MachClass_LE32::Mach_twolevel_hints_command MachLE32_twolevel_hints_command; typedef MachClass_LE64::Mach_segment_command MachLE64_segment_command; typedef MachClass_LE64::Mach_section_command MachLE64_section_command; @@ -426,6 +447,7 @@ typedef MachClass_LE64::Mach_symtab_command MachLE64_symtab_command; typedef MachClass_LE64::Mach_dysymtab_command MachLE64_dysymtab_command; typedef MachClass_LE64::Mach_segsplit_info_command MachLE64_segsplit_info_command; typedef MachClass_LE64::Mach_routines_command MachLE64_routines_command; +typedef MachClass_LE64::Mach_twolevel_hints_command MachLE64_twolevel_hints_command; typedef MachClass_BE32::Mach_ppc_thread_state Mach_ppc_thread_state; typedef MachClass_LE32::Mach_i386_thread_state Mach_i386_thread_state; @@ -454,6 +476,7 @@ protected: typedef typename MachClass::Mach_dysymtab_command Mach_dysymtab_command; typedef typename MachClass::Mach_segsplit_info_command Mach_segsplit_info_command; typedef typename MachClass::Mach_routines_command Mach_routines_command; + typedef typename MachClass::Mach_twolevel_hints_command Mach_twolevel_hints_command; public: PackMachBase(InputFile *, unsigned cpuid, unsigned filetype, @@ -581,6 +604,22 @@ protected: Mach_thread_command threado; }; +class PackDylibPPC32 : public PackMachPPC32 +{ + typedef PackMachPPC32 super; + +public: + PackDylibPPC32(InputFile *f); + + virtual int getFormat() const { return UPX_F_DYLIB_PPC32; } + virtual const char *getName() const { return "Dylib/ppc32"; } + virtual const char *getFullName(const options_t *) const { return "powerpc-darwin.dylib"; } +protected: + virtual void pack3(OutputFile *, Filter &); // append loader + virtual void pack4(OutputFile *, Filter &); // append PackHeader + virtual void buildLoader(const Filter *ft); +}; + class PackMachI386 : public PackMachBase { typedef PackMachBase super; diff --git a/src/p_mach_enum.h b/src/p_mach_enum.h index e447d87f..e36c8d03 100644 --- a/src/p_mach_enum.h +++ b/src/p_mach_enum.h @@ -70,6 +70,7 @@ LC_ID_DYLIB = 0xd, LC_LOAD_DYLINKER = 0xe, LC_ROUTINES = 0x11, + LC_TWOLEVEL_HINTS= 0x16, LC_SEGMENT_64 = 0x19, LC_ROUTINES_64 = 0x1a, LC_UUID = 0x1b, diff --git a/src/packmast.cpp b/src/packmast.cpp index f69c7241..90925316 100644 --- a/src/packmast.cpp +++ b/src/packmast.cpp @@ -281,6 +281,8 @@ Packer* PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const optio return p; if ((p = func(new PackDylibI386(f), user)) != NULL) return p; + if ((p = func(new PackDylibPPC32(f), user)) != NULL) + return p; return NULL; } diff --git a/src/stub/Makefile b/src/stub/Makefile index e5772878..bd8e72cb 100644 --- a/src/stub/Makefile +++ b/src/stub/Makefile @@ -102,6 +102,7 @@ STUBS += mips.r3000-linux.elf-fold.h STUBS += mipsel.r3000-linux.elf-entry.h STUBS += mipsel.r3000-linux.elf-fold.h STUBS += mipsel.r3000-ps1.h +STUBS += powerpc-darwin.dylib-entry.h STUBS += powerpc-darwin.macho-entry.h STUBS += powerpc-darwin.macho-fold.h STUBS += powerpc-linux.elf-entry.h @@ -1050,6 +1051,19 @@ tmp/powerpc-darwin.macho-main.o : $(srcdir)/src/$$T.c $(call tc,objdump) -dr $(tc_objdump_disasm_options) $@ | $(RTRIM) > $@.disasm +# /*********************************************************************** +# // powerpc-darwin.dylib +# ************************************************************************/ + +# info: we use the tc settings from powerpc-linux.elf +powerpc-darwin.dylib%.h : tc_list = powerpc-linux.elf default +powerpc-darwin.dylib%.h : tc_bfdname = elf32-powerpc + +powerpc-darwin.dylib-entry.h : $(srcdir)/src/$$T.S + $(call tc,gcc) -c $< -o tmp/$T.bin + $(call tc,f-embed_objinfo,tmp/$T.bin) + $(call tc,bin2h) tmp/$T.bin $@ + # /*********************************************************************** # // powerpc-linux.elf # ************************************************************************/ diff --git a/src/stub/src/powerpc-darwin.dylib-entry.S b/src/stub/src/powerpc-darwin.dylib-entry.S new file mode 100644 index 00000000..edc7ebda --- /dev/null +++ b/src/stub/src/powerpc-darwin.dylib-entry.S @@ -0,0 +1,185 @@ +/* + * powerpc-darwin.dylib-entry.S -- program entry point & decompressor (PowerPC32 dylib) + * + * This file is part of the UPX executable compressor. + * + * Copyright (C) 2005-2009 John F. Reiser + * All Rights Reserved. + * + * UPX and the UCL library are free software; you can redistribute them + * and/or modify them under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. + * If not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * John F. Reiser + * + * + */ + +#include "arch/powerpc/32/macros.S" +#include "arch/powerpc/32/ppc_regs.h" + +/************************************************************************* +// We have been CALLed as a subroutine from dyld; C-language rules apply. +// -4*4+_start: .long offset(user_init_function) +// -3*4+_start: .long offset(b_info of compressed Mach_headers) +// -2*4+_start: .long length(compressed __TEXT) +// -1*4+_start: .long 8+ total_length # 8+ number of preceding bytes in file +**************************************************************************/ + + section MACOS000 +_start: .globl _start + mflr r2 + call main # must be exactly 1 instruction; link_register= &decompress +decompressor: + section NRV_HEAD +SZ_DLINE=128 # size of data cache line in Apple G5 + +/* PowerPC has no 'cmplis': compare logical [unsigned] immediate shifted [by 16] */ +#define hibit r0 /* holds 0x80000000 during decompress */ + +#define src a0 +#define lsrc a1 +#define dst a2 +#define ldst a3 /* Out: actually a reference: &len_dst */ +#define meth a4 + +#define off a4 +#define len a5 +#define bits a6 +#define disp a7 + + section NRV2E +#include "arch/powerpc/32/nrv2e_d.S" + + section NRV2D +#include "arch/powerpc/32/nrv2d_d.S" + + section NRV2B +#include "arch/powerpc/32/nrv2b_d.S" + +#include "arch/powerpc/32/lzma_d.S" + + section NRV_TAIL +eof_nrv: +#define dst0 a4 +#define tmp a1 + lwz dst0,0(ldst) // original dst + mtlr t3 // return address + subf a0,lsrc,src + subf tmp,dst0,dst // -1+ dst length + addi a0,a0,1 // return 0: good; else: bad [+1: correct for lbzu] + addi tmp,tmp,1 // dst length + stw tmp,0(ldst) +#undef tmp + +// CACHELINE=32 is the observed minimum line size of any cache. +// Some caches may have larger lines, but it is cumbersome to lookup +// {AT_DCACHEBSIZE, AT_ICACHEBSIZE, AT_UCACHEBSIZE: /usr/include/elf.h}, +// then save the correct size in a variable {where to put it?}, or to modify +// the two instructions here. If a cache has larger lines, then we expect +// that the second dcbst (or icbi) on a the same line will be fast. +// If not, then too bad. + + section CFLUSH // In: a2=dst= &highest stored byte; a4=dst0= &lowest stored byte +CACHELINE=32 + ori dst0,dst0,-1+ CACHELINE // highest addr on cache line +cfl_nrv: + dcbst 0,dst0 // initiate store (modified) cacheline to memory + cmpl cr0,dst0,dst // did we cover the highest-addressed byte? + icbi 0,dst0 // discard instructions from cacheline + addi dst0,dst0,CACHELINE // highest addr on next line + blt cr0,cfl_nrv // not done yet +#undef dst0 + sync // wait for all memory operations to finish + isync // discard prefetched instructions (if any) +cfl_ret: + ret + + section ELFMAINY + // IDENTSTR goes here + + section ELFMAINZ +sz_b_info= 12 + sz_unc= 0 + sz_cpr= 4 + b_method= 8 + +PROT_NONE =0x00 +PROT_READ =0x01 +PROT_WRITE =0x02 +PROT_EXEC =0x04 + +MAP_SHARED =0x1 +MAP_PRIVATE =0x2 +MAP_ANON =0x1000 + +SYS_mmap =197 +SYS_mprotect= 74 + +main2: + teq r0,r0 // debugging + stwu r2,-4*(1+ 32-a0)(sp) # retaddr + stmw a0,4*1(sp) + mflr r31 # r31= &decompressor + lwz r29, -4*1(r31) # "call main" at _start + lwz r30,-4*1+ _start - decompressor(r31) # 4+ offset(_start) + rlwinm r29,r29,0,6,29 # 4+ main - decompressor + add r30,r30,r29 # offset(main); ASSUMES (8+_start)==decompressor + addi r29,r29,-4 # main - decompressor + + li a0,0 # addr + mr a1,r30 # length + li a2,PROT_READ|PROT_WRITE + li a3,MAP_ANON|MAP_PRIVATE + li a4,-1 + li a5,0 # hi32(offset) + li a6,0 # lo32(offset) + li 0,SYS_mmap + sc + li a0,-1 # failure + teq r0,r0 // debugging + + + li a2,main - movup2 + mtctr a2 + add a1,a0 ,r30 # lwa(dst); new_page + offset(main) + add a0,r29,r31 # lwa(src); &main +movup1: # descending copy [moveup2, main) + lbzu r0,-1(a0) + stbu r0,-1(a1) + bdnz+ movup1 + + subf a2,a2,r30 # offset(movup2) + mtlr a1 # &copied movup2 + mtctr a2 # offset(movup2) + blr # goto the copied code + +movup2: # descending copy [base, movup2) + lbzu r0,-1(a0) + stbu r0,-1(a1) + bdnz+ movup2 + + subf r31,a0,r31 + add r31,a1,r31 # relocated decompressor + + teq r0,r0 +main: + b main2 +dy_top: +len_top = dy_top - main + +/* +vi:ts=8:et:nowrap +*/ + diff --git a/src/stub/tmp/powerpc-darwin.dylib-entry.bin.dump b/src/stub/tmp/powerpc-darwin.dylib-entry.bin.dump new file mode 100644 index 00000000..1eefe199 --- /dev/null +++ b/src/stub/tmp/powerpc-darwin.dylib-entry.bin.dump @@ -0,0 +1,52 @@ +file format elf32-powerpc + +Sections: +Idx Name Size VMA LMA File off Algn Flags + 0 MACOS000 00000008 00000000 00000000 00000034 2**0 CONTENTS, RELOC, READONLY + 1 NRV_HEAD 00000000 00000000 00000000 0000003c 2**0 CONTENTS, READONLY + 2 NRV2E 00000148 00000000 00000000 0000003c 2**0 CONTENTS, RELOC, READONLY + 3 NRV2D 0000012c 00000000 00000000 00000184 2**0 CONTENTS, RELOC, READONLY + 4 NRV2B 000000f0 00000000 00000000 000002b0 2**0 CONTENTS, RELOC, READONLY + 5 LZMA_ELF00 0000008c 00000000 00000000 000003a0 2**0 CONTENTS, RELOC, READONLY + 6 LZMA_DEC10 0000099c 00000000 00000000 0000042c 2**0 CONTENTS, READONLY + 7 LZMA_DEC20 0000099c 00000000 00000000 00000dc8 2**0 CONTENTS, READONLY + 8 LZMA_DEC30 00000020 00000000 00000000 00001764 2**0 CONTENTS, READONLY + 9 NRV_TAIL 0000001c 00000000 00000000 00001784 2**0 CONTENTS, READONLY + 10 CFLUSH 00000024 00000000 00000000 000017a0 2**0 CONTENTS, READONLY + 11 ELFMAINY 00000000 00000000 00000000 000017c4 2**0 CONTENTS, READONLY + 12 ELFMAINZ 00000098 00000000 00000000 000017c4 2**0 CONTENTS, READONLY +SYMBOL TABLE: +00000000 l d LZMA_DEC30 00000000 LZMA_DEC30 +00000000 l d NRV_TAIL 00000000 NRV_TAIL +00000000 l d ELFMAINZ 00000000 ELFMAINZ +00000000 l d MACOS000 00000000 MACOS000 +00000000 l d NRV_HEAD 00000000 NRV_HEAD +00000000 l d NRV2E 00000000 NRV2E +00000000 l d NRV2D 00000000 NRV2D +00000000 l d NRV2B 00000000 NRV2B +00000000 l d LZMA_ELF00 00000000 LZMA_ELF00 +00000000 l d LZMA_DEC10 00000000 LZMA_DEC10 +00000000 l d LZMA_DEC20 00000000 LZMA_DEC20 +00000000 l d CFLUSH 00000000 CFLUSH +00000000 l d ELFMAINY 00000000 ELFMAINY +00000000 g MACOS000 00000000 _start + +RELOCATION RECORDS FOR [MACOS000]: +OFFSET TYPE VALUE +00000004 R_PPC_REL24 ELFMAINZ+0x00000094 + +RELOCATION RECORDS FOR [NRV2E]: +OFFSET TYPE VALUE +000000b4 R_PPC_REL14 NRV_TAIL + +RELOCATION RECORDS FOR [NRV2D]: +OFFSET TYPE VALUE +000000b4 R_PPC_REL14 NRV_TAIL + +RELOCATION RECORDS FOR [NRV2B]: +OFFSET TYPE VALUE +00000090 R_PPC_REL14 NRV_TAIL + +RELOCATION RECORDS FOR [LZMA_ELF00]: +OFFSET TYPE VALUE +00000004 R_PPC_REL14 LZMA_DEC30+0x00000020