Importing C Code Into SM64 Using n64chain and armips
Getting C code into N64 ROMs is easier than you might think using n64chain and armips. This thread will show you how to set them up and build a Hello World example for SM64.

Setting up n64chain and armips

Follow these steps to install n64chain and armips and prepare them for command line usage.

  1. Download n64chain from and extract all the files from the 'tools' folder to to C:\n64chain\ (Your directory should look like this)
  2. Download the latest armips build from and extract armips.exe to C:\n64chain\bin\armips.exe
  3. Download n64crc from and move it to C:\n64chain\bin\n64crc.exe
  4. Add n64chain, n64crc, and armips to the system path by doing the following:
    1. Click the Windows start button, type "environment variables" in the search bar and open "Edit environment variables for your account"
    2. You should see a variable called "PATH" under user variables, click it and click "Edit..."
    3. (Win7) Add ;C:\n64chain\bin to the end of the variable value and click OK
      (Win10) Click "New", add C:\n64chain\bin and click OK
Note: I could not find an official binary for n64crc so I compiled myself. Its source code is at I did not use "Real N64 CRC Tool"/"rn64crc" for this tutorial because it produces invalid checksums for ROMs with the 6103 bootcode (e.g. Paper Mario).

After the path variable has been updated, you may need to restart your computer for the change to take effect.

Simple Hello World

Here is a minimalist Hello World example that overwrites one of the game's useless functions with code of our own. Create a folder containing the following files, and also drop an original SM64 ROM named "Super Mario 64 (U) [!].z64" in the folder.
You can download this archive which contains everything except the ROM.

Here we create declarations for a few functions and variables in SM64 so they can be referenced from our C code.
Later we will tell armips their addresses by defining labels for them in sm64.asm.
extern void PrintStr(int x, int y, const char* text); // 0x802D6554
extern short g_MarioCoins; // 0x8033B218
extern short g_MarioHealth; // 0x8033B21E

// Tell armips' linker where the assets we declared in sm64.h are located
.definelabel PrintStr, 0x802D6554
.definelabel g_MarioCoins, 0x8033B218
.definelabel g_MarioHealth, 0x8033B21E

#include "sm64.h"

// This hello_world function will overwrite one of SM64's useless functions, which happens to be called once every frame

void hello_world(void)
    // Print HELLO WORLD to the screen
    PrintStr(20, 20, "HELLO WORLD");
    // Also kill Mario if he gets 5 or more coins, for science
    if(g_MarioCoins >= 5)
        g_MarioHealth = 0;

Note: armips' linker exposes symbols both ways, so if we wanted to make our own call to this function from custom assembly code we could just use jal hello_world.

.n64 // Let armips know we're coding for the N64 architecture
.open "Super Mario 64 (U) [!].z64", "Super Mario 64 (U) [!].mod.z64", 0 // Open the ROM file
.include "sm64.asm" // Include sm64.asm to tell armips' linker where to find the game's function(s)
.headersize 0x80245000 // Set the displacement between ROM and RAM addresses
.org 0x802CB1C0 // Set the origin to the RAM address of the useless debug function
.area 0xA4, 0 // Define an area the size of the useless function to ensure we can't overwrite anything else
.importobj "hello_world.o" // Import and link the compiled C object, overwriting the useless function with our new code
.close // Close the ROM file

mips64-elf-gcc -Wall -O1 -mtune=vr4300 -march=vr4300 -mabi=32 -fomit-frame-pointer -G0 -c hello_world.c
armips main.asm
n64crc "Super Mario 64 (U) [!].mod.z64"

After the files are prepared, run build.bat. This should build a new ROM file called "Super Mario 64 (U) [!].mod.z64" which contains the Hello World program. If you run the ROM and go to the castle grounds, you should see this:

Spoiler alert: Mario does die if he grabs 5 coins.

For reference, here's the assembly and data n64chain generates. Note that armips' linker will put the data sections (in this case, the "HELLO WORLD" text) immediately after the code.

I made a more advanced makefile setup here: This setup combines all C objects into a single library and imports it over the padding bytes in ROM / the unused 80370000 area in RAM. It can be configured to load elsewhere by editing this line. (So no need to import over unused functions!)
aglab2 liked this post
This was very helpful, great work!
aglab2 liked this post
old notes:

/* Constants - struct pointers */
#define M64_CURR_OBJ_PTR            0x80361160   /* Pointer to object being currectly processed */
#define M64_FIRST_OBJ_STRUCT        0x8033D488   /* Pointer to the first object (out of 240) in the circular linked list */
#define M64_MARIO_STRUCT            0x8033B170   /* you can read it from 0x8032d93c */
#define M64_MARIO_OBJ_PTR           0x80361158   /* Pointer to Mario OBJ struct in RAM */
#define M64_LEVEL_STRUCT            0x8033B90c

/* Constants - misc pointers */
#define M64_DISPLAY_STATS_FLAGS     0x8032b26a
#define M64_SEGMENT_TABLE           0x8033b400
#define M64_CURRENT_LEVEL_ID        0x8032ddf8 /* u16 */
#define M64_GEO_LAYOUT_PTR_TABLE    0x8032ddc4 /* Pointer to pointer */
#define DEBUG_FLAG1                 0x8032d598

/* graph flags */
#define BILLBOARD 4
#define INVISIBLE 0  /* recheck */
#define VISIBLE   1  /* recheck */

//library function:

extern int sprintf ( char * str, const char * format, ... );          
/* Functions */
extern int   CreateMessageBox(u16 flags, u16 rotate_to_mario, u16 type_of_dialog, u16 message_id);
/* CreateMessageBox                                          */
/* return value = 0x00 -> dialog is happening                */
/*                0x01 -> dialog is over (choice #1)         */
/*                0x02 -> dialog is over (choice #2)         */
/*                0x03 -> normal dialog is over              */
/* type of dialog = 0xA1 -> save related (wing blocks?)      */
/*                  0xA2 -> regular dialog                   */
/*                  0xA3 -> two choices                      */
/*   You may want to set an wrapper function for             */
/*   CreateMessageBox (check yoshi.c for an example)         */

extern int   CreateStar(float x, float y, float z);   /* returns pointer for spawned object */
extern void  CopyObjParams(u32 *dest, u32 *source);  /* copies X,Y,Z + rotation from another object */
extern void  CopyObjPosition(u32 *dest, u32 *source);
extern void  CopyObjRotation(u32 *dest, u32 *source);
extern void  CopyObjScaling(u32 *dest, u32 *source);
extern int   DeactivateObject(u32 obj_pointer); /* kills current object */
extern float DistanceFromObject(u32 object1, u32 object2);  /* usually object 1 = (*Obj) and object 2 = Mario */
extern void  DmaCopy(u32 dst, u32 bottom, u32 top);
extern void  ExplodeObject(u32 obj_ptr);
extern void  PlaySound(u32 argument);
extern void  HideObject();  /* hides current object by ORing 0x01 at offset 0x02 */
extern void  UnHideObject(); /* ORs 0x10*/
extern int   RotateTorwardsMario(int current_rotation, int rotation_speed, int arg2);
extern void  ScaleObject(float global_scaling_factor);
extern void  ScaleXYZ(u32 obj_pointer, float x, float y, float z);
extern void  SetModel(u16 model_ID);  /* change how the object looks */
extern int   SetObjAnimation(u16 animation_index);
extern int   ShakeScreen(u16 argument); /* argument = 1 to 4 (?) */
extern int   SpawnObj(u32 obj_pointer, u16 model_id, u32 behavior);   /* returns pointer for spawned object */
extern int   CheckObjBehavior(u32 behavior_segmented_pointer); /* return 1 if behavior == arg, else 0  */
extern int   CheckObjBehavior2(u32 obj_pointer, u32 behavior_segmented_pointer); /* return 1 if behavior == arg, else 0  */
extern void  SetObjBehavior(u32 obj_pointer, u32 behavior_segmented_pointer); /* 0x802a14c4 */
extern int   IsMarioStepping(); /* returns 1 if Mario is on TOP of a solid object, else 0 */
extern void  ProcessCollision(); /* 0x803938cc, usually called from behaviors */
extern int   SetMarioAction(u32 mario_struct_pointer, u32 action, u32 unk_arg);  /* to Do: check return values */

extern int  ProcessGeoLayout(u32 *dest, u32 segmented_address);   /* 0x8037e0b4 */

/* Music Related */
extern int  SetMusic(u32 layer, u16 song_index, u32 a2); /* possible layers = 0 (main bgmusic), 1 (other musics) or 2 (sfx) */
extern int  SetInstrument(u32 *chan_ptr, u8 instrument_index);

/* these functions need to be tested further */
extern void  CreateTextBox(u16 msg_ID);
extern int   PrintText(u32 x_pos, char *text, u32 fade); /* used in Credits. a2 = a float value ? */
extern int   PrintRegularText(u32 x, u32 y, char *table_text_pointer);  /* needs to be tested */
extern int   StopMario(u16 arg);  /* 1 = stop mario  2 = do nothing??
/* print functions */
extern void  PrintInt (u16 x, u16 y, char* text, u32 value);
extern int   PrintRegularText(u32 x, u32 y, char *table_text_pointer);  /* needs to be tested more, used at credits?*/
extern void  PrintXY(u16 x, u16 y, char* text);

/* memory functions */
extern int   SegmentedToVirtual(u32 segmented_pointer);   /* returns RAM pointer of a segmented address*/
extern int   GetSegmentBase(int segment);
extern int   SetSegmentBase(int segment, void *base);  /* sets segment pointer table */
extern u8    *DynamicIndexCopy(u32 index, u32 begin, u32 end, u32 what);

/* math stuff */
extern float sqrtf(float x);
extern float sinf(float x);
extern float cosf(float x);

typedef struct anim /* unfinishied */
    u16 framecount; /* 0x08 */
    u32 pointer;    /* 0x0c */
    u32 pointer2;   /* 0x10 */
} Animation;

typedef struct anim2
    u32 *AnimationDMATable;    // 0xd1 items, each item 8 bytes in lenght
    u32 Current_DMA;           // not sure
    u32 TargetAnimationPtr;    // 0x80060030 - gets copied to MarioObj->animation (that's where's animation data is DMAed)
    u32 padding;
} MarioAnimation;

extern int   SetMarioAnimation(MarioAnimation *AnimStruct, u16 index); /* returns 1 if animation has changed, 0 if its the same as before) */

typedef struct Music2
   u32 _0x00;
   u32 _0x04;
   u32 _0x08;
   u32 _0x0c;
   u32 _0x10;
   u32 _0x14;
   u32 _0x18;
   u32 _0x1c;
   f32 volume;       /* 1 = 0x7f  -  0x20 */
   f32 _0x024_maybe_pan;
   f32 _0x028;
   f32 pitch_transposition;
   u32 _0x30;
   u32 _0x34;
   u32 _0x38;
   u32 instrument;   /* pointer to instrument */
   /* stuff missing here */
   u32 Vibrato;      /* 0x70 */

} ChannelStruct;

typedef struct Music1
    u32 _0x00;
    u32 _0x04;
    u16 _0x08;
    u16 tempo;        /* 0x0a */
    u32 _0x0c;
    u32 _0x10;
    u32 pointer_seq_head;
    f32 volume;
    u32 _0x1c;
    f32 _0x20;
    f32 _0x24;
    u32 _0x28;
    ChannelStruct *Channel[15];
    u32 _0x7c_sequence_pointer;
} MusicController;          /* Layer 0 = 0x80222618 */

typedef struct collision_triangle
    u16 collision_type;   /* check collision.txt */
    u16 _0x02;
    u8 flag;
    u8 _0x05;
    s16 ymin;
    s16 ymax;
    s16 vertex1_x, vertex1_y, vertex1_z;   /* 0x0a */
    s16 vertex2_x, vertex2_y, vertex2_z;   /* 0x10 */
    s16 vertex3_x, vertex3_y, vertex3_z;   /* 0x16 */
    float normal_x;
    float normal_y;
    float normal_z;
    float negdot;
    u32 _0x2c;   /* unused? */
} CollisionTriangle;

typedef struct pad_struct  /* from nagra */
    s16 stick_x;
    s16 stick_y;
    float x;
    float y;
    float z;
    u16 currentButton;      /* 0x10 */
    u16 previousButton;
    u32 *statusData;          /* 0x14 */
    u32 *controllerData;    /* 0x18 */
} Pad;

typedef struct camera_struct  /* mario->camera (0x8033C520) */
    u32 mario_action;       /* copied from mario->action */
    float x;               /* also copied from Mario struct */
    float y;
    float z;
    s16 _0x10_mario_0x2c;  /* 0x10 */
    u16 rotation;          /* again copied from Mario struct */
    s16 _0x14_mario_0x30;
    s16 _0x16_mario_0x32;
    u32 _0x18;
    u16 _0x1c;
    u16 camera_setting;    /* 0x06 = door opening   0x09 = triggers initial peach animation */
     /* incomplete, many other members left ?? */
} Camera;

typedef struct level_struct /* 0x8033B90c, from Cellar Dweller's notes */
    s16 _0x00;
    s16 terrain_type;
    u32 geo_layout_ptr;
    u32 collision_ptr;
    u32 _0x0c;
    u32 mini_objects_ptr;         /* 0x10 pointer to an array of objects defined by command 0x39 */
    u32 warp_links_head;
    u32 _0x18;
    u32 _0x1c;
    u32 *objects_head;           /* 0x24 objects linked list head */
    u32 LevelCameraPointer;   /* Level Camera Pointer (generated at run-time) */
    u32 _0x28;
    u32 _0x2c;
    u32 _0x30;
    u8 _0x34;         /* set by level command 0x30 */
    u8 _0x35;
    s16 music_param;      /* 0x36 */
    s16 music_param2;     /* 0x38 title screen,etc) */
    /* more? */
} Level;

typedef struct object_struct           /* Regular objects, Mario also has its own struct like this */
    u16    graph_node_type;        /* 0x00 */
    u16    graph_flags;
    struct object_struct *prev;                  /* previous linked list object */
    struct object_struct *next;                  /* next linked list object */
    u32    graph_parent;
    u32    graph_child;            /* 0x10 */
    u32    geo_layout_ptr;         /* 0x14 */
    u32    _0x18;
    u32    _0x1c;
    float  _0x20;             /* 0x20 */
    float  _0x24;
    float  _0x28;
    float  x_scaling;              /* 0x2c */
    float  y_scaling;              /* 0x30 */
    float  z_scaling;
    u16    _0x38;
    u16    _0x3a;
    u32    animation;              /* 0x3c - current animation */
    u16    anim_current_frame;     /* 0x40 */
    u16    anim_timer;             /* timer, animation related? */
    u16    anim_current_frame_copy;
    u16    _0x46;
    u32    _0x48;
    u32    _0x4c;
    u32    matrix_ptr;             /* 0x50 */
    float  float_0x54;
    float  float_0x58;
    float  float_0x5c;
    struct object_struct  *next_object_ptr;        /* 0x60: re-check this */
    u32    _0x64;
    struct object_struct  *next_object_ptr2;       /* 0x68: re-check this (child_obj) */
    u32    _0x6c;
    u32    _0x70;                  /* 0x70 */
    u16    active;                 /* 0x0000 = inactive, 0x0101 = active */
    u16    _0x76;                  /* collision flag according to YE */
    struct object_struct  *collided_obj_ptr;      /* according to YE, pointer to object collided with */
    u32    _0x7c;
    u32    _0x80;                  /* 0x80 */
    u32    _0x84;
    u32    _0x88;
    u32    obj_flags;
    u32    _0x90;                  /* 0x90 */
    u32    _0x94;
    u32    _0x98;
    u32    _0x9c;
    float  x_pos;                  /* 0xa0 */
    float  y_pos;
    float  z_pos;
    float  x_speed;  /* x increment? */
    float  y_speed;                  /* 0xb0 */
    float  z_speed;  /* z_increment? */
    float  speed;
    u32    _0xbc;
    u32    _0xc0;                  /* 0xc0 */
    u32    x_rotation;             /* 0xc4 - rotation triplet */
    u32    y_rotation;             /* 0xc8 */
    u32    z_rotation;
    u32    x_rotation2;            /* rotation copy (collision?) 0xd0 */
    u32    y_rotation2;            /* 0xd4 */
    u32    z_rotation2;
    u32    _0xd8;
    u32    _0xe0;                  /* 0xe0 */
    float  _0xe4;         /* gravity related? y_speed - 0xe4 ? */
    u32    _0xe8;
    u32    _0xec;
    u32    _0xf0;                  /* 0xf0 */
    u32    _0xf4;               /* obj type for some behaviors (ie, ice bully), for AMPS, radius of rotation */
    u32    _0xf8;
    u32    _0xfc;
    u32    _0x100;                 /* 0x100 */
    u32    _0x104;
    u32    _0x108;
    u32    _0x10c;
    u32    _0x110;                 /* 0x110 */
    u32    _0x114;
    u32    _0x118;
    u32    _0x11c;
    u32    animation_ptr;        /* 0x120 = (set by 0x27 26 behavior command) entry for animation? */
    u32    _0x124;                  /* in some behaviors, action related? */
    float  _0x128;
    float  _0x12c;
    u32    interaction;            /* 0x130
                                      00 = Something Solid. Can't grab. Mario walks around, Can jump over.
                                      01 = Crashed when jumping at it, Used by Hoot.
                                      02 = Grabbing
                                      04 = Going through door
                                      08 = Knocks mario back and dissappears. No damage.
                                      10 = Something Solid, Can't grab, Mario walks around, Can't jump over, Seems somewhat thin..
                                      40 = Climbing
    u32    _0x134;
    u32    _0x138;
    u32    _0x13c;
    u32    _0x140;                 /* 0x140 */
    u32    behav_param;            /* behav param */
    u32    _0x148;
    u32    action;
    u32    _0x150;                 /* 0x150 = also reset when action changes */
    u32    timer;                  /* always incremented. When action changes, it's set to 0 */
    float  _0x158;                
    float  distance_from_mario;
    u32    _0x160;                 /* 0x160 */
    float  _0x164_x;
    float  _0x168_y;
    float  _0x16c_z;
    float  _0x170;                 /* 0x170 */
    float  _0x174;
    u32    _0x178;
    u32    transparency;
    u32    damage_to_mario;        /* According to YE, "How many segments of damage to do to Mario for objects that cause him harm" */
    u32    health;                 /* Health (ie, for King bob-omb and whomp */
    u32    behav_param2;           /* re-check */
    u32    previous_action;        /* used to reset the 0x154 timer */
    u32    _0x190;                 /* 0x190 */
    float  collision_distance;     /*  NOTE: if collision_distance < disappear_distance then disappear_distance = collision_distance */
    u32    _0x198;
    float  drawing_distance;
    u32    _0x1a0;                 /* 0x1a0 */
    u32    _0x1a4;
    u32    _0x1a8;
    u32    _0x1ac;
    u32    _0x1b0;                 /* 0x1b0 */
    u32    _0x1b4;
    u32    _0x1b8;
    u32    _0x1bc;
    u32    _0x1c0;                 /* 0x1c0 */
    u32    _0x1c4;
    u32    _0x1c8;
    u32    script_ptr;
    u32    stack_index;            /* 0x1d0 */
    u32    stack;
    u32    _0x1d8;
    u32    _0x1dc;
    u32    _0x1e0;                 /* 0x1e0 */
    u32    _0x1e4;
    u32    _0x1e8;
    u32    _0x1ec;
    u32    _0x1f0;                 /* 0x1f0 */
    u16    _0x1f4;
    u16    _0x1f6;
    float  col_sphere_x;
    float  col_sphere_y;
    float  _0x200;                 /* 0x200 */
    float  _0x204;
    float  _0x208;
    u32    behavior_script_entry;
    u32    _0x210;                 /* 0x210 */
    u32    collide_obj_ptr;        /* pointer to another object (collision happening)?.
                                   Can be used to detect if Mario is on top of the object by comparing
                                   value with Mario's pointer */
    u32    collision_ptr;          /* set by behavior script (0x2A command) */
    u32    _0x21c;
    u32    _0x220;                 /* 0x220 */
    u32    _0x224;
    u32    _0x228;
    u32    _0x22c;
    u32    _0x230;                 /* 0x230 */
    u32    _0x234;
    u32    _0x238;
    u32    _0x23c;
    u32    _0x240;                 /* 0x240 */
    u32    _0x244;
    u32    _0x248;
    u32    _0x24c;
    u32    _0x250;                 /* 0x250 */
    u32    _0x254;
    u32    _0x258;
    u32    behav_param_copy_ptr;
} Object;

typedef struct mario_struct                /* 8033b170 */
    u32    status;
    u32    flags;                   /* cap & other flags */
    u32    _0x08;
    u32    action;                  /* see Romanian Girl list */
    u32    previous_action;         /* 0x10 */
    u32    _0x14;
    u16    _0x18;
    u16    _0x1a;
    u32    _0x1c;    
    float  _0x20;                   /* 0x20 */
    u16    _0x24;                    /* rotation related, if bit 1 of status is set, 0x24 is copied to 0x2e */
    s16    hitstun;                 /* hitstun counter (how long Mario stays invencible after getting hit */
    u32    _0x28;
    s16    _0x2c;
    u16    rotation;                /* divide it by 180 to get the angle? */
    s16    _0x30;                   /* 0x30 */
    s16    _0x32;    
    u32    _0x34;
    u32    _0x38;
    float  x_pos;                   /* 0x3c */
    float  y_pos;                   /* 0x40 */
    float  z_pos;
    float  x_speed;
    float  y_speed;
    float  z_speed;                 /* 0x50. The next four floats are related to speed/acelleration */
    float  speed;
    float  _0x58;
    float  _0x5c;    
    u32    _0x60;                   /* 0x60 */
    u32    _0x64;
    CollisionTriangle  *curr_collision_triangle;  /* current triangle mario is stepping in */
    float  _0x6c;    
    float  ground_y;                   /* 0x70 - ground Y */
    u32    _0x74;                  
    u32    _0x78;
    u32    _0x7c;    
    u32    _0x80;                   /* 0x80 */
    u32    _0x84;
    Object   *MarioObj;
    u32    _0x8c_ptr;    
    u32    Mario_level_command;     /* 0x90 = 8033b4b0 = Information read from the Level command that sets Mario*/
    Camera *camera;
    u32    _0x98_ptr;               /* 0x8033B3B0 */
    Pad    *pad;                    /* pointer to controller struct  controller 1 = 8033AF90   controller2 = 8033AFAC*/
    MarioAnimation *MarioAnimationStruct;   /* 0x8033B080 */
    u32    _0xa4;
    s16    coins;                   /* 0xa8 */
    s16    stars;                   /* 0xaa */
    s16    lifes;                   /* 0xac */
    s16    power;                   /* 0xae */
    u16    constant_ground_distance;   /* usually 0xBD */
    u16    misc_timer;              /* on any value other than zero it will decrease until zero (also, drains mario energy?) */
    u32    cap_timer;
    u32    _0xb8;
    float  _0xbc;    
    float  _0xc0;                   /* 0xc0 */    
} MarioStruct;

sprintf = 0x8032255c ;
   CreateMessageBox = 0x802A4BE4 ;
   CreateTextBox = 0x802d8d08 ;
   CreateStar = 0x802F2B88 ;
   CheckObjBehavior = 0x802a14fc;
   CheckObjBehavior2 = 0x802A1554;
   SetObjBehavior = 0x802a14c4;
   CopyObjParams = 0x8029F0E0 ;
   CopyObjPosition = 0x8029F120 ;
   CopyObjRotation = 0x8029F148 ;
   CopyObjScaling = 0x8029F3A4 ;
   DistanceFromObject = 0x8029e27c ;
   DeactivateObject = 0x802a0568 ;
   DmaCopy = 0x80278504 ;
   ExplodeObject = 0x802e6af8 ;
   GetSegmentBase = 0x80277f20 ;
   HideObject = 0x8029F620 ;
   UnHideObject = 0x8029f6bc ;
   PlaySound = 0x802ca190;
   PrintInt = 0x802d62d8 ;
   PrintXY = 0x802d66c0 ;
   RotateTorwardsMario = 0x8029e530 ;
   ScaleObject = 0x8029F430;
   ScaleXYZ =  0x8029F3D0;
   SegmentedToVirtual = 0x80277f50;
   SetModel = 0x802a04c0;
   SetSegmentBase = 0x80277ee0 ;
   SetObjAnimation = 0x8029f464;
   ShakeScreen = 0x802a50fc ;
   SpawnObj = 0x8029edcc ;
   SetMarioAction = 0x80252cf4;
   SetMarioAnimation = 0x80279084;
   IsMarioStepping = 0x802A3CFC ;
   DynamicIndexCopy = 0x8027868c ;
   ProcessGeoLayout = 0x8037e0b4;
   MoveRelated = 0x802a2320 ;
   PreMoveObj = 0x802a1308;
   MoveObj = 0x802A2348 ;
   MoveObj2 = 0x802A2644 ;
   UnknownMove = 0x8029E714 ;
   _8037a9a8 = 0x8037a9a8;
   StopMario = 0x8028bd34 ;
   PrintText = 0x802d8844;
   PrintRegularText = 0x802d7e88;
   sinf = 0x80325480;
   cosf = 0x80325310;
   sqrtf = 0x80323a50;
   ProcessCollision = 0x803839cc;
   SetMusic = 0x80320544;
   SetInstrument = 0x8031cfd4;
aglab2 liked this post
You can also use regular LLVM clang instead of gcc. No building from source or toolchain is required, just download it from here: Link

It has very good linker unlike armips that can do proper Link-Time Optimization and has C++ support from box.

I am using the following set of files to build things, I will notice several important things in forum: GitHub Repository 

I mostly similar to GCC CFLAGS but I also add several important flags to remove exceptions, RTTI and some other useless MIPS stuff. Here are they
CFLAGS = -Wall -Wdouble-promotion -Os -mtune=vr4300 -march=mips2 --target=mips-img-elf -fomit-frame-pointer -G0 -I $(INCLUDE_PATH) -mno-check-zero-division -fno-exceptions -fno-builtin -fno-rtti -fno-common -mno-abicalls

For linking I use ld.ldd with custom ldscript. You might want to change if you would like to make behaviors be at static place for example. In my example, I use the fact that 0x1200000 is DMACopy'd to 0x80400000 and I put my binaries to 0x1208000 with behavior being at the beginning. Extern symbols are specified in symbols.ld file which is based on frauber's answer and could be enlarged on demand. Headers I use are made to be C++ compliable with float triplet being put as a struct for convenience.

This is LD script I use for linking, to specify object file you could add another section and set it to needed object file like xd.o(.data)
INCLUDE symbols.ld


 .sm64 0x80408000 :

The following way might be a bit harder in general for beginner but it has more power than armips+gcc. One can follow Makefile in repo for more in-depth information
Say I wanted to add more functions/variables. Would I need to find the functions and add the addresses to the header file and asm?
(06-06-2019, 09:09 AM)nole Wrote: Say I wanted to add more functions/variables. Would I need to find the functions and add the addresses to the header file and asm?

just compile it to mips assembly then load the mips code to ram and jal to its ram address youre loading it in from some other function you want to jump to your custom function from
I honestly don't know anything about jal. I've done some basic hacking with cheatEngine and can code in c. Would learning more about mips help?
(06-14-2019, 03:33 AM)nole Wrote: I honestly don't know anything about jal. I've done some basic hacking with cheatEngine and can code in c. Would learning more about mips help?
For sure, general mips hacking knowledge applies and it will help you with debugging

Users browsing this thread: 1 Guest(s)