I'm reverse engineering firmware from an old sampler/groovebox that uses a Hitachi SuperH-3 7706 processor, making great progress. Out of the 8M or so of code, everything looks and lines up correctly. However, in a few spots I see some stuff that makes me scratch my head and I'm not sure what is going on...

This function looks a lot like another one in a different area, which eventually calls memcpy(). This version of it makes a jsr to the middle of a function (0x8C010D20) and doesn't make a lot of sense given what is being stuffed into the function argument registers (see 0x80018e82 for actual jsr). And the 0x400B is definitely a jsr r0.

Here is the disassembly of the caller and the callee. What am I missing here?

-- Caller --
                     *                          FUNCTION                          *
                     undefined __stdcall rom_copy_to_ram_maybe(int param_1)
     undefined         r0:1           <RETURN>
     int               r4:4           param_1
     undefined4        Stack[-0x4]:4  local_4                                 XREF[1]:     80018e70(*)
     undefined4        Stack[-0x8]:4  local_8                                 XREF[2]:     80018e72(*),
80018e70 2f e6           mov.l      r14,@-r15=>local_4
80018e72 4f 22           sts.l      pr,@-r15=>local_8
80018e74 24 48           tst        param_1,param_1
80018e76 d5 06           mov.l      @(DAT_80018e90,pc),r5=>DAT_a0400000              = A0400000h
80018e78 8f 01           bf/s       LAB_80018e7e
80018e7a 6e f3           _mov       r15,r14
80018e7c d5 05           mov.l      @(DAT_80018e94,pc),r5=>SUB_a0000000              = A0000000h
                     LAB_80018e7e                                    XREF[1]:     80018e78(j)
80018e7e d0 06           mov.l      @(->FUN_8c010d20,pc),r0                          = 8c010d20
80018e80 d4 06           mov.l      @(PTR_DAT_80018e9c,pc),param_1=>DAT_8d800000     = 8d800000
80018e82 40 0b           jsr        @r0=>FUN_8c010d20                                TODO: this makes no sense... it'
80018e84 00 09           _nop
80018e86 6f e3           mov        r14,r15
80018e88 4f 26           lds.l      @r15=>local_8+,pr
80018e8a 00 0b           rts
80018e8c 6e f6           _mov.l     @r15+,r14
80018e8e 00 09           nop
                     DAT_80018e90                                    XREF[2]:     rom_copy_to_ram_maybe:80018e76(R
80018e90 a0 40 00 00     undefined4 A0400000h
                     DAT_80018e94                                    XREF[2]:     rom_copy_to_ram_maybe:80018e7c(R
80018e94 a0 00 00 00     undefined4 A0000000h
                     PTR_FUN_80018e98                                XREF[2]:     rom_copy_to_ram_maybe:80018e7e(R
80018e98 8c 01 0d 20     addr       FUN_8c010d20
                     PTR_DAT_80018e9c                                XREF[2]:     rom_copy_to_ram_maybe:80018e80(R
80018e9c 8d 80 00 00     addr       DAT_8d800000

-- Callee --
                     *                          FUNCTION                          *
                     uint __stdcall FUN_8c010d10(char param_1)
     uint              r0:4           <RETURN>
     char              r4:1           param_1
     undefined4        Stack[-0x4]:4  local_4                                 XREF[1]:     8c010d10(*)
                     FUN_8c010d10                                    XREF[4]:     8c010a82(c), 8c010b14(*),
                                                                                  8c010cec(c), 8c010d08(*)
8c010d10 2f e6           mov.l      r14,@-r15=>local_4
8c010d12 74 bf           add        -0x41,param_1
8c010d14 64 4c           extu.b     param_1,param_1
8c010d16 e1 19           mov        #0x19,r1
8c010d18 34 16           cmp/hi     r1,param_1
8c010d1a 8f 02           bf/s       LAB_8c010d22
8c010d1c 6e f3           _mov       r15,r14
8c010d1e a0 01           bra        LAB_8c010d24
                     *                          FUNCTION                          *
                     undefined FUN_8c010d20()
     undefined         r0:1           <RETURN>
                     FUN_8c010d20                                    XREF[2]:     rom_copy_to_ram_maybe:80018e82(c
8c010d20 e0 00           _mov       #0x0,r0
                     LAB_8c010d22                                    XREF[1]:     FUN_8c010d10:8c010d1a(j)
8c010d22 e0 01           mov        #0x1,r0
                     LAB_8c010d24                                    XREF[1]:     FUN_8c010d10:8c010d1e(j)
8c010d24 6f e3           mov        r14,r15
8c010d26 00 0b           rts
8c010d28 6e f6           _mov.l     @r15+,r14
8c010d2a 00 09           nop
8c010d2c 00 09           nop
8c010d2e 00 09           nop```
  • can you paste disassembly as text instead of pictures? use code formatting option – Igor Skochinsky Oct 7 '19 at 17:10
  • @IgorSkochinsky it seems putting it all as text her is going way over the limit for a comment, I've pasted the code here pastebin.com/kqx5QL01 – telengard Oct 7 '19 at 22:06
  • You should edit the question, not put everything in the comment – Igor Skochinsky Oct 8 '19 at 6:04

I'm not 100% sure I'm reading it right but it seems FUN_8c010d20 performs a part of the epilog processing:

  1. Copy r14 (frame pointer) to r15 (stack pointer)
  2. pop (saved?) r14 from the stack and return.

I'm not sure why this is done in a separate function instead of inline but I suspect it may be caused by over-aggressive "shared code" optimization (sometimes also called reverse inlining), when the compiler (or more commonly linker) scans the binary for common code sequences (especially at the end of functions) and replaces them by calls to a common function to reduce total code size. This can bring substantial code size savings but in this case it basically replaced two instructions by a function call which itself takes more space (especially if we add the 4-byte function address literal).

  • That definitely seems to be what it is doing, but given all the setup in rom_copy_to_ram_maybe, including putting values in the registers for function arguments, it seems odd that nothing is done. 8c010d20 is in the middle of the function at a label (setting r0 to 0), then falls through to the other label (sets r0 to 1) and then returns. Seems like a lot of setup for what amounts to either a NOP or returning a 1. – telengard Oct 8 '19 at 14:45
  • @telengard maybe check if code is being copied around or some memory remapping is going on – Igor Skochinsky Oct 8 '19 at 15:07
  • I will go over it again, I've spent a lot of time reversing to the point I'm pretty confident with the memory map and any code being copied around (which does happen). thanks. I guess that confirms that what is going on doesn't totally look right. :) – telengard Oct 8 '19 at 20:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.