2

I think I'm really brain-dead and am not really sure what to do next, but I am trying to manually convert assembly code to a C program. It's not really working, but I'm not sure what is wrong. I would be glad for any help. The code consists of two .c files and one header file for the subroutine. In the header file, I only declared the extern int b variable, so I'm not posting it here.

program code


build/program-mips:     file format elf32-tradbigmips


Disassembly of section my_text:

00405060 <subroutine_fnc>:
  405060:   27bdfff8    addiu   sp,sp,-8
  405064:   afbe0004    sw  s8,4(sp)
  405068:   03a0f025    move    s8,sp
  40506c:   afc40008    sw  a0,8(s8)
  405070:   8fc20008    lw  v0,8(s8)
  405074:   00000000    nop
  405078:   2842005b    slti    v0,v0,91
  40507c:   10400006    beqz    v0,405098 <subroutine_fnc+0x38>
  405080:   00000000    nop
  405084:   8fc20008    lw  v0,8(s8)
  405088:   00000000    nop
  40508c:   28420041    slti    v0,v0,65
  405090:   10400004    beqz    v0,4050a4 <subroutine_fnc+0x44>
  405094:   00000000    nop
  405098:   8fc20008    lw  v0,8(s8)
  40509c:   1000000c    b   4050d0 <subroutine_fnc+0x70>
  4050a0:   00000000    nop
  4050a4:   3c020041    lui v0,0x41
  4050a8:   8c4260d0    lw  v0,24784(v0)
  4050ac:   00000000    nop
  4050b0:   24430001    addiu   v1,v0,1
  4050b4:   3c020041    lui v0,0x41
  4050b8:   ac4360d0    sw  v1,24784(v0)
  4050bc:   8fc20008    lw  v0,8(s8)
  4050c0:   00000000    nop
  4050c4:   24420020    addiu   v0,v0,32
  4050c8:   afc20008    sw  v0,8(s8)
  4050cc:   8fc20008    lw  v0,8(s8)
  4050d0:   03c0e825    move    sp,s8
  4050d4:   8fbe0004    lw  s8,4(sp)
  4050d8:   27bd0008    addiu   sp,sp,8
  4050dc:   03e00008    jr  ra
  4050e0:   00000000    nop

004050e4 <toplevel_fnc>:
  4050e4:   27bdffc8    addiu   sp,sp,-56
  4050e8:   afbf0034    sw  ra,52(sp)
  4050ec:   afbe0030    sw  s8,48(sp)
  4050f0:   03a0f025    move    s8,sp
  4050f4:   1000001e    b   405170 <toplevel_fnc+0x8c>
  4050f8:   00000000    nop
  4050fc:   83c20028    lb  v0,40(s8)
  405100:   00000000    nop
  405104:   00402025    move    a0,v0
  405108:   0c101418    jal 405060 <subroutine_fnc>
  40510c:   00000000    nop
  405110:   00021600    sll v0,v0,0x18
  405114:   00021603    sra v0,v0,0x18
  405118:   a3c20028    sb  v0,40(s8)
  40511c:   24040001    li  a0,1
  405120:   27c20028    addiu   v0,s8,40
  405124:   00402825    move    a1,v0
  405128:   24060001    li  a2,1
  40512c:   24020fa4    li  v0,4004
  405130:   0000000c    syscall
  405134:   afc70018    sw  a3,24(s8)
  405138:   afc20024    sw  v0,36(s8)
  40513c:   8fc20018    lw  v0,24(s8)
  405140:   00000000    nop
  405144:   14400004    bnez    v0,405158 <toplevel_fnc+0x74>
  405148:   00000000    nop
  40514c:   8fc20024    lw  v0,36(s8)
  405150:   10000002    b   40515c <toplevel_fnc+0x78>
  405154:   00000000    nop
  405158:   2402ffff    li  v0,-1
  40515c:   afc20020    sw  v0,32(s8)
  405160:   8fc20020    lw  v0,32(s8)
  405164:   00000000    nop
  405168:   04400018    bltz    v0,4051cc <toplevel_fnc+0xe8>
  40516c:   00000000    nop
  405170:   00002025    move    a0,zero
  405174:   27c20028    addiu   v0,s8,40
  405178:   00402825    move    a1,v0
  40517c:   24060001    li  a2,1
  405180:   24020fa3    li  v0,4003
  405184:   0000000c    syscall
  405188:   afc70018    sw  a3,24(s8)
  40518c:   afc2001c    sw  v0,28(s8)
  405190:   8fc20018    lw  v0,24(s8)
  405194:   00000000    nop
  405198:   14400004    bnez    v0,4051ac <toplevel_fnc+0xc8>
  40519c:   00000000    nop
  4051a0:   8fc2001c    lw  v0,28(s8)
  4051a4:   10000002    b   4051b0 <toplevel_fnc+0xcc>
  4051a8:   00000000    nop
  4051ac:   2402ffff    li  v0,-1
  4051b0:   afc20020    sw  v0,32(s8)
  4051b4:   8fc30020    lw  v1,32(s8)
  4051b8:   24020001    li  v0,1
  4051bc:   1062ffcf    beq v1,v0,4050fc <toplevel_fnc+0x18>
  4051c0:   00000000    nop
  4051c4:   10000002    b   4051d0 <toplevel_fnc+0xec>
  4051c8:   00000000    nop
  4051cc:   00000000    nop
  4051d0:   3c020041    lui v0,0x41
  4051d4:   8c4260d0    lw  v0,24784(v0)
  4051d8:   03c0e825    move    sp,s8
  4051dc:   8fbf0034    lw  ra,52(sp)
  4051e0:   8fbe0030    lw  s8,48(sp)
  4051e4:   27bd0038    addiu   sp,sp,56
  4051e8:   03e00008    jr  ra
  4051ec:   00000000    nop

program data


build/program-mips:     file format elf32-tradbigmips

Contents of section my_data:
 4160d0 00000000                             ....      

Here is the code I retrieved so far:

Toplevel

#include <stdio.h>
#include "subroutine.h"


int b = 0;
int toplevel_fnc(void)
{
  char a = 0;
  while (b < 0)
  {
    read(0, a, 1);
    a = 3;
    if (a != 1)
    {
      (long)b;
      a = subroutine_fnc(b);
      write(1,a,1);
      b += 4;
    }
  }
  return b;
}

Subroutine

/* Implementation of the subroutine subroutine_fnc */

#include "subroutine.h"



int subroutine_fnc(int a)
{
  if (90 < a)
  {
    return a;
  }
  if (64 < a)
  {
    b += 1;
    a += 32;
    return a;
  }
}
3
  • 1
    IDA PRO 7.5 then press F5 and problem should be solved.
    – SSpoke
    Jul 3 '21 at 3:48
  • Or in Ghidra ctrl+e Jul 13 '21 at 8:17
  • best option is to like mentioned above use especially ghidra for mips pseudo c and edit that pseudo code into something more operate able and compile able. Are you just doing this for self knowledge and learning for for application? Dec 31 '21 at 16:29
3

It's not really working, but I'm not sure what is wrong.

More information could help give more specific answers like what exactly is the behavior of the original program and what behavior is your compiled code producing?

Have you compiled your program and compared the output assembly to see where it is similar and where it differs?

I would also suggest on your first pass to not attempt to rewrite the logic too much and follow one branch at a time before reconstructing the meat. For example your subroutine_fnc:

40506c:   afc40008    sw  a0,8(s8)
405070:   8fc20008    lw  v0,8(s8)
405074:   00000000    nop
405078:   2842005b    slti    v0,v0,91
40507c:   10400006    beqz    v0,405098 <subroutine_fnc+0x38>
...
405098:   8fc20008    lw  v0,8(s8)
40509c:   1000000c    b   4050d0 <subroutine_fnc+0x70>
...
4050d0:   03c0e825    move    sp,s8
4050d4:   8fbe0004    lw  s8,4(sp)
4050d8:   27bd0008    addiu   sp,sp,8
4050dc:   03e00008    jr  ra

We take a0 (usually the first argument) and save it to 8(s8). Then load 8(s8) into v0. slti v0, v0, 91 is the equivalent of if(v0<91) v0=1 else v0=0 and then beqz v0, 405098 is "go to 405098 if v0 is equal to 0". 405098 loads 8(s8) back into v0 then unconditionally branches (jumps) to 4050d0. From here we have post-amble; restoring the value of s8, restoring the stack pointer, and returning to what called us. Keep in mind generally v0 is a register that MIPS uses to return values from so we'll just assume for now that's what is going on (pretty much confirmed by looking at the instruction immediately following the original call to subroutine_fnc where it makes use of v0 at 405110).

So in C that one branch is something akin to:

int subroutine_fnc(int a) {
   if (a < 91) {
      ...
   }
405098:
   return a;
}

Continuing on in the other direction of the first branch:

405080:   00000000    nop
405084:   8fc20008    lw  v0,8(s8)
405088:   00000000    nop
40508c:   28420041    slti    v0,v0,65
405090:   10400004    beqz    v0,4050a4 <subroutine_fnc+0x44>
405094:   00000000    nop

Reload 8(s8) into v0, if(v0<65) v0=1 else v0=0, "go to 4050a4 if v0 is equal to 0". If we don't take this branch, we land at 405098 which we've already covered so that leaves us something like:

int subroutine_fnc(int a) {
   if (a < 91) {
      if ( a < 65 ) {
          goto 405098:
      }
      4050a4:   3c020041    lui v0,0x41
      4050a8:   8c4260d0    lw  v0,24784(v0)
      4050ac:   00000000    nop
      4050b0:   24430001    addiu   v1,v0,1
      4050b4:   3c020041    lui v0,0x41
      4050b8:   ac4360d0    sw  v1,24784(v0)
      4050bc:   8fc20008    lw  v0,8(s8)
      4050c0:   00000000    nop
      4050c4:   24420020    addiu   v0,v0,32
      4050c8:   afc20008    sw  v0,8(s8)
      4050cc:   8fc20008    lw  v0,8(s8)
   }
405098:
   return a;
}

Now that we've got the branches covered and being pretty simple, we can clean the logic up to get rid of that goto.

int subroutine_fnc(int a) {
   if (a < 91) {
      if ( a >= 65 ) {
          4050a4:   3c020041    lui v0,0x41
          4050a8:   8c4260d0    lw  v0,24784(v0)
          4050ac:   00000000    nop
          4050b0:   24430001    addiu   v1,v0,1
          4050b4:   3c020041    lui v0,0x41
          4050b8:   ac4360d0    sw  v1,24784(v0)
          4050bc:   8fc20008    lw  v0,8(s8)
          4050c0:   00000000    nop
          4050c4:   24420020    addiu   v0,v0,32
          4050c8:   afc20008    sw  v0,8(s8)
          4050cc:   8fc20008    lw  v0,8(s8)
      }
   }
   return a;
}

And if you really want you could clean that up one step further by making it if ( a < 91 && a >= 65 ) {

At this point however you can see you've got the branching logic wrong before even confirming what the actual computations are. The reason your subroutine_fnc jumped out at me is what happens in your code if a is greater than 90?

Disclosure, I don't remember MIPS much. I used this instruction reference and this register reference.

2

Generating Pseudo-Code

You should try to use specialized programs to generate pseudo-code in C. Writing code in C from raw asm is pain and it's strongly not recommended.

Tools

  1. Ghidra (Free)
  2. IDA PRO (Paid)

If you realy need to write it manually for some reasons I sugesst to use dissasemblers which will display asm in nice looking graph what should really help you. For example:

  1. Ghidra
  2. IDA FREE
  3. Cutter

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.