Page 1 of 1

elfpatcher - GNU way to develop binary code patches

Posted: Tue Feb 16, 2010 4:35 pm
by tom_van
When I started development of arfix for sh4 I looked for inspiration to Newages' arm code.
He used Kiel arm tools - I doubt that Kiel provide them for free and I'm not aware of a sh4 version.
So let's use the power of gnu tools, it is sufficient.

Reimplementing of whole C function

It is a little bit heavy-weight patching. You have to analyze more code and dependencies.
It pays of for shorter functions, because you can comfortably write in C
and you get full control what function do. Another advantage particularly in sh4 exeDSP
is that you get usually enough space for your new code: original code is compiled
without optimization(!!) and you can use -Os option (optimize for size)
You should tell gcc you want the function in extra code segment:

Code: Select all

int STMovie_SetDisplaySize(int fit)
    __attribute__ ((section("patch1STMovie_SetDisplaySize")));
int STMovie_SetDisplaySize(int fit)
{
  // your code
  int iw = videoInputWidth;
  STVID_GetInputWindowMode(handle, &mode, &pi);
}
You have to declare all functions and variables used as always in C.


Assembly language
Of course you can use assembly language to replace shorter fragment of code.
On sh4 there is a limitation that segment is always aligned to even word.
If you need start at odd word, you have to include one instruction preceding your change.
Unfortunately gnu linker cannot compute sh4 relative jumps to different segment,
so if you want to use them, awkward math is necessary:

Code: Select all

        .equ PatchStartLoc, 0xd167c8
        .equ CheckPositiveLoc, 0xd16840
        .section patch2ChangeToNextZoomOption,"ax",@progbits
PatchStart:
        cmp/pl r0
        bt      CheckPositiveLoc + PatchStart - PatchStartLoc /*instead of CheckPositive, which you could use if it were in same segment*/
 
        .section patch3ChangeToNextZoomOption,"ax",@progbits
CheckPositive:

Linking
You should tell the linker where your new code will reside.
Use option

Code: Select all

--section-start=patch1STMovie_SetDisplaySize=0x56f43c
or much better write your own ld script.
In the script you can also check if your replaced function fits in limited space:

Code: Select all

OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux")
OUTPUT_ARCH(sh)
SECTIONS
{
  .patch1 0x56f43c : { *(patch1STMovie_SetDisplaySize) *(.rodata*) }
  ASSERT( . <= 0x56fa28, "STMovie_SetDisplaySize is too big to fit into exeDSP")
 
  .patch2 0xd167c8 : { *(patch2ChangeToNextZoomOption) }
  ...
Linker also needs to know addresses of original functions and variables you've referenced.
If your exeDSP has symbols like arm versions, the easy way is use it for linking

Code: Select all

--just-symbols=exeDSP
Unfortunately this is not the case on sh4 - there is statically linked and fully striped exeDSP.
Then you can use option

Code: Select all

--defsym=videoInputWidth=0x221020c
or include the address to ld script

Code: Select all

 STVID_GetInputWindowMode = 0x9a6168;
As patch has no initialization code and hopefully neither needs libraries, link with options

Code: Select all

-nostartfiles -nostdlib
As a complete example use arfix package in oe svn - will be committed soon.


You've just compiled and linked your shiny patch. Got elf binary. What now?
Traditional way is convert it to hex by objcopy utility and patch exeDSP somehow.


gdb can load a patch
If you used gdb/gdbserver for getting info from exeDSP, just stop the program, load the elf
and then jump to last address of program execution. Continue will not work
as it use 'start address' of just loaded elf.


elfpatcher
Users of your patch don't want to start gdb - they don't know what the hell it is.
That's why I take a programmers exercise and write this short program.
It is 3-in-one function actually.

1) You can patch running program in memory using ptrace() call in similar way as gdb does.
Actually program is stopped for couple of miliseconds while elfpatcher is changing it.
Ideal for testing without worries of TV bricking.

2) You can patch elf binary without fiddling with address offset.
If exeDSP is on writable filesystem, elfpatcher works directly in TV (you should stop exeDSP first). Tested in my LE46A956
On linux PC can be used to prepatch firmware.

3) Additional functions like checking if patch is applied and hexedecimal output of original
and new data.

Code: Select all

$ build/tmp/work/i686-linux/elfpatcher-native-1.0-r1/elfpatcher
 
elfpatcher 1.0
Takes one or more elf32 files and writes the content of segments named .patch*
Patching a binary file is potentially dangerous, use solely at your own risk
 
Usage:
        elfpatcher [-v] -p pid elf-patch-file...
        elfpatcher [-v] [-c] -e original-elf-file elf-patch-file...
 
-p pid.... stops running process using PTRACE, patches text or data
           in process memory and continues the process
-e file... writes patches to appropriate segments of elf32 file
-c........ do not write, just check if patches are applied
-v........ verbose: shows hex representation of patch
-v -v..... double verbose: shows original data before applying patches too
Source is available in SamyGO svn, oe branch-0-0-1
Hope it helps even to the arm powered majority.

Re: elfpatcher - GNU way to develop binary code patches

Posted: Wed Feb 17, 2010 11:18 pm
by erdem_ua
It's better to write this article to Wiki page :)
Thanks.

Re: elfpatcher - GNU way to develop binary code patches

Posted: Thu Feb 18, 2010 9:17 am
by sorcerer1
Thank you for elfpatcher code!

But I think better and simpler exeDSP patching solution will be not to use binary patches but installing our own hooks at runtime as arvfix2 does. To apply patches automatically we just need to create a simple library linked with exeDSP with LD_PRELOAD (and compiled with -init option to be called at startup). Library executes code from other libraries by requests by some UNIX socket.

Re: elfpatcher - GNU way to develop binary code patches

Posted: Thu Feb 18, 2010 5:28 pm
by tom_van
Sorcerer1, the problem is I know a little about arm versions as you do about sh4 ones.
T-RBYDEUC exeDSP is static executable without symbols and does not call ld.so
- so there is no function of LD_... env variables, no way to preload anything
sorcerer1 wrote:Library executes code from other libraries by requests by some UNIX socket.
It does not look simpler to me... :roll:

erdem_ua wrote:It's better to write this article to Wiki page
Let's discuss the topic first and copy to wiki later...

Re: elfpatcher - GNU way to develop binary code patches

Posted: Fri Feb 19, 2010 6:26 am
by sorcerer1
tom_van, its a bit more complex without symbols. :) But try to compile some library with -shared -Wl,-init,initfunc. If you create initfunc(), then it will be called at startup. Just LD_PRELOAD the library. I tried it with arm exeDSP and it works ok: I can access to the exeDSP code.

Re: elfpatcher - GNU way to develop binary code patches

Posted: Fri Feb 19, 2010 8:49 am
by tom_van
Sorcerer1, you don't want to believe :)
Short test on T-RBYDEUC:

Code: Select all

# LD_PRELOAD=nonexisting MicomCtrl
ERROR: ld.so: object 'nonexisting' from LD_PRELOAD cannot be preloaded: ignored.
==================1================
==================2================
# LD_PRELOAD=nonexisting /exe/exeDSP
[PROF] [4294783.940] PerfCheck
ST Board Init, Build Date Apr 17 2009 15:31:26
St-App Version : 2008091701
St-Ko  version : 2008120401
MicomCtrl as dynamic executable loads ld.so

Code: Select all

$ sh4-linux-readelf -l lib/modules/MicomCtrl
 ...
Program Headers:
...
  INTERP         0x000134 0x00400134 0x00400134 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
and exeDSP as static one does not.

Code: Select all

$ sh4-linux-readelf -l exe/exeDSP

Elf file type is EXEC (Executable file)
Entry point 0x400140
There are 4 program headers, starting at offset 52
 
Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00400000 0x00400000 0x158c432 0x158c432 R E 0x10000
  LOAD           0x158c434 0x0199c434 0x0199c434 0x65893c 0x8759a4 RW  0x10000
  TLS            0x158c434 0x0199c434 0x0199c434 0x00014 0x00044 R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
 
 Section to Segment mapping:
...
That's why exeDSP on sh4 does not use LD_anything. Enough? :idea:

Re: elfpatcher - GNU way to develop binary code patches

Posted: Fri Feb 19, 2010 8:59 am
by sorcerer1
tom_van, enough. :) Thank you for the explanation.

Re: elfpatcher - GNU way to develop binary code patches

Posted: Sat Feb 20, 2010 3:27 pm
by tom_van
elfpatcher v1.1 committed to SamyGO svn, oe branch-0-0-1
v1.0 has serious error in PtracePoke addressing, please upgrade to 1.1. Sorry.

Re: elfpatcher - GNU way to develop binary code patches

Posted: Sun Mar 27, 2011 5:49 pm
by tom_van
elfpatcher v1.3 committed to SamyGO svn, oe branch-0-0-1
Previous versions have serious error in PtracePoke word size, please upgrade to 1.3. Sorry.

Erdem or other admins: please move this topic to A series, as the elfpatcher is not used for other firmwares. Thanks