elfpatcher - GNU way to develop binary code patches

Ideas and dreaming will go this forum
Post Reply

tom_van
Official SamyGO Developer
Posts: 147
Joined: Tue Jan 19, 2010 10:44 am

elfpatcher - GNU way to develop binary code patches

Post 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.
User avatar
erdem_ua
SamyGO Admin
Posts: 3125
Joined: Thu Oct 01, 2009 6:02 am
Location: Istanbul, Turkey
Contact:

Re: elfpatcher - GNU way to develop binary code patches

Post by erdem_ua »

It's better to write this article to Wiki page :)
Thanks.
sorcerer1
Official SamyGO Developer
Posts: 46
Joined: Wed Jan 13, 2010 5:16 pm

Re: elfpatcher - GNU way to develop binary code patches

Post 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.
tom_van
Official SamyGO Developer
Posts: 147
Joined: Tue Jan 19, 2010 10:44 am

Re: elfpatcher - GNU way to develop binary code patches

Post 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...
sorcerer1
Official SamyGO Developer
Posts: 46
Joined: Wed Jan 13, 2010 5:16 pm

Re: elfpatcher - GNU way to develop binary code patches

Post 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.
tom_van
Official SamyGO Developer
Posts: 147
Joined: Tue Jan 19, 2010 10:44 am

Re: elfpatcher - GNU way to develop binary code patches

Post 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:
sorcerer1
Official SamyGO Developer
Posts: 46
Joined: Wed Jan 13, 2010 5:16 pm

Re: elfpatcher - GNU way to develop binary code patches

Post by sorcerer1 »

tom_van, enough. :) Thank you for the explanation.
tom_van
Official SamyGO Developer
Posts: 147
Joined: Tue Jan 19, 2010 10:44 am

Re: elfpatcher - GNU way to develop binary code patches

Post 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.
tom_van
Official SamyGO Developer
Posts: 147
Joined: Tue Jan 19, 2010 10:44 am

Re: elfpatcher - GNU way to develop binary code patches

Post 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

Post Reply

Return to “[B] Brainstorm”