0

I'm studying Mips32 for an exam and recently I was wandering how to translate a c struct in mips. I'm fairly new to mips and assembly code in general, but I have tried to gather all my knowladge to work out a solution.

Let's say I have a simple C struct:

struct Student
{
    int id;
};

int main()
{
    struct Student student;
    student={111111};
    return 0;
}

What I have in mind is to store all data in the stack, like that:

sub $sp,$sp,4
li  $t1,111111
sw  $t1,($sp)

and if I have more than one student, I simply create a routine that stores the arguments in the stack. I have a problem though, how can I keep track of all the students? maybe with a frame pointer ?

I don't know if that is the appropriate way to represent a struct in mips, let me know if there are better solutions.

dragosht
  • 3,237
  • 2
  • 23
  • 32
PurpleKiwi
  • 90
  • 7

3 Answers3

2

I have a problem though, how can I keep track of all the students? maybe with a frame pointer ?

You don't need a frame pointer to keep track of all the students.  Further, the problem of keeping track of them is not unique to their being struct's — you would have the same problem keeping track of many of integers.  And further still, the problem of keeping track of many items is also not unique to assembly.

What you need is either a separate variable for each item (often impractical, especially if the number of items is variable), or, a data structure: a collection of some sort, e.g. an array or linked list, for example.


With a separate local variables in C each needs a different name, and, in assembly each would have a different offset/location in the stack frame.  Stack space for all would be allocated in one instruction, and they all be referenced via their individual offset from the stack pointer.

A frame pointer can be used if you like, but since with MIPS the stack space for a function's stack frame is all allocated in one instruction in function prologue, the stack pointer doesn't otherwise move during the function's body — and that means that the individual variables remain at constant offsets from the stack pointer.


A frame pointer can be helpful if either:

  • the machine doesn't do stack relative offsets well, but does frame pointer relative offsets easily, or,
  • the machine requires frequent pushing and popping that move the stack pointer, which changes the offsets needed to access the same locations in the stack frame — a frame pointer remains constant regardless of pushing and popping.  (Pushing and popping may be used for argument passing, and/or temporary storage if there are insufficient CPU registers, e.g. during expression evaluation.)
  • A function dynamically allocate stack space, e.g. via C's alloca.

Broadly speaking, the first two do not apply to MIPS, so functions generally don't need a frame pointer.


Alternatively, you can use a data structure like an array to keep track of many items.  The array itself needs to be referred to by a variable (in C, a name, and in assembly an offset) — but at least there's only one variable regardless of how many items to keep track of.  And then you're down to indexing to access the individual elements.  (Indexing involves computing the address of the elements, and depends on the size of the elements, but otherwise operates the same for an int array vs. a struct array.)

Erik Eidt
  • 23,049
  • 2
  • 29
  • 53
  • Thanks for the detailed answer. If I have understood correctly the easiest way to represent a struct is to use a collection and if I want to use the stack the frame pointer is useless (unless I have to dynamicly allocate memory) – PurpleKiwi Feb 08 '20 at 11:09
  • Yes, but you only need a collection for multiple items. A single struct can be stored in memory or registers just like an int. – Erik Eidt Feb 08 '20 at 13:15
0

your data can be local, static or dynamically allocated. There is no one rule. See: https://godbolt.org/z/gfDVD8

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

typedef struct
{
    int x;
    int y[4];
    char name[23];
}MYSTRUCT_t;



MYSTRUCT_t my_global_struct[10];

void my_global_struct_foo(void)
{
    for(size_t pos = 0; pos < 10; pos++)
    {
        my_global_struct[pos].x = rand();
        my_global_struct[pos].y[0] = my_global_struct[pos].x / 2;
        my_global_struct[pos].name[4] = my_global_struct[pos].y[0];
    }
}

void my_static_struct_foo(void)
{
    static MYSTRUCT_t my_static_struct[10];

    for(size_t pos = 0; pos < 10; pos++)
    {
        my_static_struct[pos].x = rand();
        my_static_struct[pos].y[0] = my_static_struct[pos].x / 2;
        my_static_struct[pos].name[4] = my_static_struct[pos].y[0];
    }
}

void my_local_struct_foo(void)
{
    volatile MYSTRUCT_t my_local_struct[10];

    for(size_t pos = 0; pos < 10; pos++)
    {
        my_local_struct[pos].x = rand();
        my_local_struct[pos].y[0] = rand();
        my_local_struct[pos].name[4] = rand();
    }
}
0___________
  • 60,014
  • 4
  • 34
  • 74
0

A good idea here would be to allocate some space with the .space , then align it via the .align n directive (be cautious MIPS needs word alignment) and then just load the address of this memory area in your "main:".

Let's assume that you would like to allocate space for 10 Students:

std_struct: .align 2
           .space 40   # 10students, 1 word=4 bytes each
.text

main:

la $s0, std_struct #now everything should be parsable via $s0 register
apfel
  • 31
  • 3
  • `.align` needs to be on a separate line, and *before* the `.space`. (It can be after the label; classic MIPS assembly magically lets `.align` insert padding *before* the previous label) – Peter Cordes Feb 07 '20 at 18:24
  • Ok, so basically std_struct is a collection of students and I can parse them by adding 4bytes*n at the address. Can you explain me the role of .align 2? – PurpleKiwi Feb 08 '20 at 10:53
  • 1
    @PeterCordes comment is pretty much right here, I mistyped that. Concerning the .align n directive it will align the first byte of the 40-byte block into the next available address that is multiple of 2^n. This procedure is related with the so-called "word alignment" in MIPS, which basically requires every variable's allocated space to start on an address which is a multiple of the sizeof(typeof(variable)). – apfel Feb 08 '20 at 20:22
  • Yes, I know what `.align` does in MARS / MIPS assembly, even though that's [somewhat different from "normal" assemblers](https://stackoverflow.com/questions/59926448/mars-mips-simulators-built-in-assembler-aligns-more-than-requested/59926496#59926496) . Was the 2nd half of your comment supposed to be a reply to the OP, @PurpleKiwi? – Peter Cordes Feb 08 '20 at 20:28
  • @PeterCordes yes I didn't know how to use it – PurpleKiwi Feb 08 '20 at 20:34
  • @PeterCordes definitely, though I never mentioned him – apfel Feb 08 '20 at 20:37