The MIPS assembly code generated by mips-gcc almost, but doesn't quite, run on the Mars MIPS simulator. For example:
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.)
MARS (MIPS Assembler and Runtime Simulator) An IDE for MIPS Assembly Language Programming.
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 .
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With