4

Long question, sorry in advance. Okay, so I'm working with a few unusual constraints which is why I haven't found much help online so far. The main constraint is that I can not use an emulator, and therefore I can not use syscalls. I need to do a few things with MIPS and C and don't know enough about how these programs are executed to understand how to get them to work the way I need them to. Firstly, as per my professor's instructions, I need to create a file called "rng.s". He also specifies that it should begin with the following code:

.abicalls
.option pic0
.globl rng, seed
.set nomips16

As I understand it, this means that I am creating two functions "rng" and "seed", and I don't need to create a main function. In a template provided for earlier assignments, there was some code that looked like this:

.ent main
.type main, @function

And I'm unsure about whether or not I need to do something similar here with my functions rng and seed. Furthermore, when I don't include main the assembler kicks back an error. Later on in the assignment I am supposed to write a C program that calls the function rng() (the same one written in my MIPS program) and pass it some values. I don't quite understand how to call rng() from inside of my C program. At first I tried it like this:

#include<stdio.h>

int main(int argc, char* argv[])
{
    //int a, b, c are input from command line using atoi(argv)
    //i've tested it and that part works fine, so it's not important
    rng(a, b, c);
    return 0;
}

My professor included a Makefile that is supposed to compile both programs into one executable file, but if I try to use this, I get an error because there are multiple declarations of main.

So the big question is how do I get my MIPS program to run without main? And then how do I call the function inside of my MIPS program from inside of my C program?

I've already spent two days on this and I've gotten nowhere, so any help would be greatly appreciated. Thank you.

  • Find documentation for MIPS ABI (the professor may have given some references) or just see what assembly code gcc generates for main() that calls your functions (see options `-c`, `-S`). – Alexey Frunze Nov 22 '15 at 09:33
  • I have some trouble in understanding, on which architecture you mix C and MIPS. There is a reason, why MIPS is usually run in an emulator on a typical PC. – grek40 Nov 22 '15 at 10:51
  • As I understand it, when both programs are turned into object files, it doesn't really matter how it got there, the files are now capable of operating on the architecture of the machine which did the compiling/assembling, and therefore are capable of working together. So I believe the Makefile runs my MIPS program through an assembler and my C program through gcc. I guess it's mostly an exercise in figuring out how to make these programs communicate. I just need to understand the nuances of how to facilitate that communication. – Matthew Harris Nov 22 '15 at 11:24
  • I can imagine compiling C into the MIPS architecture, but compiling MIPS into native x86 sounds a bit unbelievable. That issue aside, you are right that you should be concerned about creating the object files rather than dealing with the results. It should be perfectly possible to create an object file from MIPS that does not contain a main method. If you are unsure how to do it, you may want to 'cheat' a bit by programming `rng` into a separate .c file and compile it into target assembly code. – grek40 Nov 22 '15 at 11:36
  • I _could_ do that, if I was only focused on results, but since this is an assignment, my professor will be looking over all of my source code. So I have to do it the way that I'm instructed. Not to worry though, I think I've got it figured out. Turns out, as you said, I don't need to declare a main, I can declare rng the same way that I declare main. If I do this and try to compile the MIPS program alone then the compiler will throw an error, but if I use the Makefile that compiles both programs together, then it understands that main has been declared in the C program and compiles just fine. – Matthew Harris Nov 22 '15 at 12:18

1 Answers1

0

Okay, so it's taken me a while but I finally came out with the answer. I know that a lot of this is probably pretty simple, but I'm just going to put this out there for the sake of any poor souls who are as confused as I was. So here is what I found out for both questions:

1: How to run my MIPS program without main

When the program is assembled, there needs to be a main somewhere. When assembled alone, the program needs to have main declared in the header. Like so:

.abicalls
.option pic0
.globl main
.set nomips16
.ent main
.type main, @function

This tells your program that main is a function and that you are entering it at main.

However if you are using something like a Makefile in order to incorporate different programs into one finished product, then it is possible to not declare main in your MIPS program, and instead declare main in a different program, which will be compiled at the same time. In this case, you simply need to do the same thing you would for main, but with the function that you will start at (the function you want to run first when you execute the program) like so:

.abicalls
.option pic0
.globl rng, seed
.set nomips16
.ent rng
.type rng, @function

Notice how I used .globl rng, seed. As I understand it, this allows you to call both functions (rng and seed) from other programs that are compiled into the finished product.

2: How to call functions written in my MIPS program from my C program

The C example posted in the question will do the trick. As it turns out, the MIPS program will take those arguments (a, b, c) and put them into registers $a0-$a2. Then you just need to format your program to put a return value into $v0 which can then be fed back into the C program. As an example:

// C Program
//=========================
#include<stdio.h>
int main()
{
    printf("%d", rng(0));
    return 0;
}
//=========================

// MIPS program
//=========================
rng:
    addi $v0, $a0, 1
    jr   $ra
//=========================

Running the C program will simply output 1 because it calls rng() which adds 1 to the input (found in $a0 which the C program set as 0) and puts it in $v0 before exiting. Then printf prints what rng returned, which was 1.

So there you have it. Thanks for your help Internet.