Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tweak mips-gcc output to work with MARS

The MIPS assembly code generated by mips-gcc almost, but doesn't quite, run on the Mars MIPS simulator. For example:

  • The compiler generates "j $31" instead of "jr $31"
  • The compiler puts .align directives in the text segment, which Mars does not allow.

In addition, the generated assembly is not quite set up so that it will start and stop properly (i.e., no sycall 10 at the end).

These problems are all appear to be easily fixable with a simply script; but, before I re-invent the wheel, I was wondering: (1) Are there any gcc flags that will make some of these problems go away? (2) Does anybody know of an existing program that will fix up the mips-gcc output so that it will run on Mars?

(FWIW, I see the same behavior on both gcc 3.3.6 and 4.6.1.)

like image 872
Zack Avatar asked Oct 24 '12 15:10

Zack


People also ask

What does Mars stand for in MIPS?

MARS (MIPS Assembler and Runtime Simulator) An IDE for MIPS Assembly Language Programming.

How do I compile C in MIPS?

You would need to download the source to binutils and gcc-core and compile with something like ../configure --target=mips ... . You may need to choose a specific MIPS target. Then you could use mips-gcc -S .


1 Answers

Are there any gcc flags that will make some of these problems go away?

Short answer is no. Mars uses custom system calls and is very different in calling conventions.

Does anybody know of an existing program that will fix up the mips-gcc output so that it will run on Mars?

I don't know of any automated way to convert it. You can do it only manually. I have done it actually.

Roughly, these are the steps I followed: 0. Use GobBolt compiler explorer to get a beatified raw assembly of your code. They don't use specific gcc options to get this beatified view according to this, so I'm not mentioning any gcc command, but you can set up a local copy of it.

  1. Replace all the syscalls and their calling conventions according to this : https://courses.missouristate.edu/kenvollmar/mars/help/syscallhelp.html
  2. Replace/add the required segment labels (such as .text, .data etc.) along with their required data.
  3. If you have a main function (label) add j main after .text. (4. Optionally, you can rename the registers to be more readable because as Peter Cordes mentioned in the comments, gcc for mips doesn't support the argument -mregnames)

This is an example I made, it lacks main cause it was intended as a library :

C code :

#include <stdio.h>

#include <stdlib.h>

typedef struct node Node; 

struct node {
    int data;
    struct node *left; 
    struct node *right;
};

Node *new_node (int data) { 
    Node *ret = malloc (sizeof (Node)); ret->left = NULL;
    ret->data = data;
    ret->left = NULL;
    ret->right = NULL;

return ret; }

void link (Node *parent, Node *left, Node *right) { 
    parent->left = left; 
    parent->right = right;

}

int depth (Node *root) {

    if (root == NULL) {
        return -1;
    }

    int left = depth (root->left); 
    int right = depth (root->right);

    return 1 + (left > right? left : right);
}


int even_level_max (Node *root, int level) { 
    
    if (root == NULL) {
        return 0x80000000;
    }

    int left = even_level_max(root->left, level + 1); 
    int right = even_level_max (root->right, level + 1);
    int greater = (left > right) ? left : right;

    if (level % 2 == 0) {
        return (greater > root->data)? greater : root->data;
    } else {
        return greater;
    }
}

Godbolt code :

new_node:
        addiu   $sp,$sp,-40
        sw      $31,36($sp)
        sw      $fp,32($sp)
        move    $fp,$sp
        sw      $4,40($fp)
        li      $4,12                 # 0xc
        jal     malloc
        nop

        sw      $2,24($fp)
        lw      $2,24($fp)
        nop
        sw      $0,4($2)
        lw      $2,24($fp)
        lw      $3,40($fp)
        nop
        sw      $3,0($2)
        lw      $2,24($fp)
        nop
        sw      $0,4($2)
        lw      $2,24($fp)
        nop
        sw      $0,8($2)
        lw      $2,24($fp)
        move    $sp,$fp
        lw      $31,36($sp)
        lw      $fp,32($sp)
        addiu   $sp,$sp,40
        jr      $31
        nop

link:
        addiu   $sp,$sp,-8
        sw      $fp,4($sp)
        move    $fp,$sp
        sw      $4,8($fp)
        sw      $5,12($fp)
        sw      $6,16($fp)
        lw      $2,8($fp)
        lw      $3,12($fp)
        nop
        sw      $3,4($2)
        lw      $2,8($fp)
        lw      $3,16($fp)
        nop
        sw      $3,8($2)
        nop
        move    $sp,$fp
        lw      $fp,4($sp)
        addiu   $sp,$sp,8
        jr      $31
        nop

depth:
        addiu   $sp,$sp,-40
        sw      $31,36($sp)
        sw      $fp,32($sp)
        move    $fp,$sp
        sw      $4,40($fp)
        lw      $2,40($fp)
        nop
        bne     $2,$0,$L5
        nop

        li      $2,-1                 # 0xffffffffffffffff
        b       $L6
        nop

$L5:
        lw      $2,40($fp)
        nop
        lw      $2,4($2)
        nop
        move    $4,$2
        jal     depth
        nop

        sw      $2,24($fp)
        lw      $2,40($fp)
        nop
        lw      $2,8($2)
        nop
        move    $4,$2
        jal     depth
        nop

        sw      $2,28($fp)
        lw      $3,24($fp)
        lw      $2,28($fp)
        nop
        slt     $4,$2,$3
        beq     $4,$0,$L7
        nop

        move    $2,$3
$L7:
        addiu   $2,$2,1
$L6:
        move    $sp,$fp
        lw      $31,36($sp)
        lw      $fp,32($sp)
        addiu   $sp,$sp,40
        jr      $31
        nop

even_level_max:
        addiu   $sp,$sp,-48
        sw      $31,44($sp)
        sw      $fp,40($sp)
        move    $fp,$sp
        sw      $4,48($fp)
        sw      $5,52($fp)
        lw      $2,48($fp)
        nop
        bne     $2,$0,$L9
        nop

        li      $2,-2147483648                  # 0xffffffff80000000
        b       $L10
        nop

$L9:
        lw      $2,48($fp)
        nop
        lw      $3,4($2)
        lw      $2,52($fp)
        nop
        addiu   $2,$2,1
        move    $5,$2
        move    $4,$3
        jal     even_level_max
        nop

        sw      $2,24($fp)
        lw      $2,48($fp)
        nop
        lw      $3,8($2)
        lw      $2,52($fp)
        nop
        addiu   $2,$2,1
        move    $5,$2
        move    $4,$3
        jal     even_level_max
        nop

        sw      $2,28($fp)
        lw      $3,24($fp)
        lw      $2,28($fp)
        nop
        slt     $4,$2,$3
        beq     $4,$0,$L11
        nop

        move    $2,$3
$L11:
        sw      $2,32($fp)
        lw      $2,52($fp)
        nop
        andi    $2,$2,0x1
        bne     $2,$0,$L12
        nop

        lw      $2,48($fp)
        nop
        lw      $3,0($2)
        lw      $2,32($fp)
        nop
        slt     $4,$2,$3
        beq     $4,$0,$L10
        nop

        move    $2,$3
        b       $L10
        nop

$L12:
        lw      $2,32($fp)
$L10:
        move    $sp,$fp
        lw      $31,44($sp)
        lw      $fp,40($sp)
        addiu   $sp,$sp,48
        jr      $31
        nop

Converted Mars code :

# Registers:
# a : store results
# t : temporaries
# s : saved
# k : kernel

.text:

j main

new_node: #Node *new_node (int data)
        # prologue
        addiu   $sp,$sp,-40
        sw      $ra,36($sp)
        sw      $fp,32($sp)
        move    $fp,$sp

        sw      $a0,40($fp) # fp[40] = data

        li      $v0, 9
        li      $a0, 12 
        syscall
        sw      $v0,24($fp) # fp[24] = sbrk ( sizeof (Node = 12) )

        lw      $v0,24($fp)
        lw      $v1,40($fp) # data = fp[40]
        sw      $v1,0($v0) # ret[0] = data;

        lw      $v0,24($fp)
        sw      $zero,4($v0) # ret[4] = NULL;

        lw      $v0,24($fp)
        sw      $zero,8($v0) # ret[8] = NULL;

        # epilogue
       lw      $v0,24($fp) 
        move    $sp,$fp
        lw      $ra,36($sp)
        lw      $fp,32($sp)
        addiu   $sp,$sp,40
        jr      $ra
        nop


link: # int depth (Node *root)
        # prologue
        addiu   $sp,$sp,-8
        sw      $fp,4($sp)
        move    $fp,$sp

        #store arguments
        sw      $a0,8($fp)
        sw      $a1,12($fp)
        sw      $a2,16($fp)

        #parent -> left = left;
        lw      $v0,8($fp)
        lw      $v1,12($fp)
        sw      $v1,4($v0)
        sw      $a1,4($a0)

        # parent -> right = right
        lw      $v0,8($fp)
        lw      $v1,16($fp)
        sw      $v1,8($v0)
        sw      $a2,8($a0)

        # epilogue
        move    $sp,$fp
        lw      $fp,4($sp)
        addiu   $sp,$sp,8
        jr      $ra
        nop


depth: # int depth (Node *root)
        # prologue
        addiu   $sp,$sp,-40
        sw      $ra,36($sp)
        sw      $fp,32($sp)
        move    $fp,$sp

        sw      $a0,40($fp) # fp[40] = root
        lw      $v0,40($fp)
        
        bne     $v0,$zero,L5
        li      $v0,-1
        b       L6 #if (root == NULL) return -1;

L5:
        lw      $v0,40($fp)
        lw      $v0,4($v0) 
        move    $a0,$v0 # a0 = root -> left
        jal     depth # depth(a0)
        sw      $v0,24($fp) # fp[24] = depth(a0)

        lw      $v0,40($fp)
        lw      $v0,8($v0)
        move    $a0,$v0 # a0 = root -> right
        jal     depth # depth(a0)
        sw      $v0,28($fp) # fp[28] = depth(a0)

        lw      $v1,24($fp) # v0 = right
        lw      $v0,28($fp) # v1 = left

        slt     $a0,$v0,$v1 # a0 = v1 > v0 ? 0 : 1
        beq     $a0,$zero,L7

        move    $v0,$v1 # executed when v1 > v0
L7:
        addiu   $v0,$v0,1 # executed when v0 < v1
L6:
        # epilogue
        move    $sp,$fp
        lw      $ra,36($sp)
        lw      $fp,32($sp)
        addiu   $sp,$sp,40
        jr      $ra


even_level_max:
        # prologue
        addiu   $sp,$sp,-48
        sw      $ra,44($sp)
        sw      $fp,40($sp)
        move    $fp,$sp

        sw      $a0,48($fp) # fp[48] = root
        sw      $a1,52($fp) # fp[52] = level
        lw      $v0,48($fp)

        bne     $v0,$zero,L9
        li      $v0, 0x80000000
        b       L10 # if (root == NULL) return 0x80000000;

L9: # root != NULL
        lw      $v0,48($fp)
        lw      $v1,4($v0) # v1 = root -> left
        lw      $v0,52($fp)
        addiu   $v0,$v0,1 # v0 = level + 1
        move    $a1,$v0
        move    $a0,$v1
        jal     even_level_max
        sw      $v0,24($fp) # fp[24] = left = even_level_max(root -> left, level +1)

        lw      $v0,48($fp)
        lw      $v1,8($v0) # v1 = root -> right
        lw      $v0,52($fp)
        addiu   $v0,$v0,1 # v0 = level + 1
        move    $a1,$v0
        move    $a0,$v1
        jal     even_level_max
        sw      $v0,28($fp) # fp[28] = right = even_level_max(root -> right, level + 1)

        lw      $v1,24($fp) # v1 = right
        lw      $v0,28($fp) # v0 = left
        slt     $a0,$v0,$v1 # a0 = v1 > v0 ? 0 : 1
        beq     $a0,$zero,L11
        move    $v0,$v1
L11: 
        sw      $v0,32($fp) # fp[32] = greater

        lw      $v0,52($fp) # v0 = level
        andi    $v0,$v0,0x1 # v0 & 1
        bne     $v0,$zero,L12

        lw      $v0,48($fp) # v0 = root
        lw      $v1,0($v0) # v1 = data
        lw      $v0,32($fp)  # v0 = greater
        slt     $a0,$v0,$v1 # a0 = v1 > v0 ? 0 : 1
        beq     $a0,$zero,L10 # return greater

        move    $v0,$v1 # v0 = data
        b       L10 # return data

L12:
        lw      $v0,32($fp) # return greater
L10:
        # epilogue
        move    $sp,$fp
        lw      $ra,44($sp)
        lw      $fp,40($sp)
        addiu   $sp,$sp,48
        jr      $ra
like image 173
JAAAY Avatar answered Sep 30 '22 20:09

JAAAY