gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Multiple .c files [solved for now... <_< >_>]

#133083 - HyperHacker - Tue Jul 03, 2007 4:23 am

If I'm using the default makefile, how can I have multiple .c files? In /arm9/source I have my main source file and I want to have some others in there too instead of cramming everything into one file. Both need main.h though and this doesn't seem possible: if I include it into both, it complains about multiple definitions (even though I used #ifndef/#define/#endif to prevent this <_<), if I don't one of them complains about this and that not being defined because it's all in main.h. I can just name the other ones like file.c.foo and include them into the main file, but I thought one of the main reasons to use a makefile was to avoid that?
_________________
I'm a PSP hacker now, but I still <3 DS.


Last edited by HyperHacker on Mon Jul 09, 2007 6:16 am; edited 1 time in total

#133086 - wintermute - Tue Jul 03, 2007 4:43 am

Well, here's the thing ...

Header guards only prevent a header from being included in one source file more than once. The compiler can't tell that you already included the header in some other source file.

Headers are for typedefs, function prototypes, externs for data arrays, macros and static inline function bodies. If you put normal code or data in there then you get multiple definitions.

I highly recommend getting a good book on C/C++ and not relying on GBA/DS related tutorials. You've learned some terrible habits from some spectacularly bad tutorials.
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog

#133087 - HyperHacker - Tue Jul 03, 2007 4:45 am

wintermute wrote:
Headers are for typedefs, function prototypes, externs for data arrays, macros and static inline function bodies. If you put normal code or data in there then you get multiple definitions.
There's no code in my headers. o_O It's the typedefs and prototypes and macros that are needed in both files.
_________________
I'm a PSP hacker now, but I still <3 DS.

#133088 - StoneCypher - Tue Jul 03, 2007 4:51 am

You're creating redundant copies of exportable symbols by #including them into multiple translation units. Get a c/c++ book and look up extern. (Edited: I wrote export the first time, like a dumbass.)
_________________
Quidquid Latine dictum sit, altum Sonatur
[Images not permitted - Click here to view it]

#133092 - Dwedit - Tue Jul 03, 2007 5:50 am

ot: Does the 'export' keyword actually do anything other than cause Visual C++ to display "Internal compiler error"?
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#133099 - OOPMan - Tue Jul 03, 2007 7:41 am

Er...extern is used primarily in C programming, if I recall...

C++ is, in terms of compiler function, quite a different language...

I've not really used extern much myself...

HyperHacker's problem is kinda confusing, because I know I've done what he wants to do, often and with no problems...
_________________
"My boot, your face..." - Attributed to OOPMan, Emperor of Eroticon VI

You can find my NDS homebrew projects here...

#133103 - Rajveer - Tue Jul 03, 2007 8:12 am

Just to make sure, you're not including the source files in the makefile are you?

#133105 - Cearn - Tue Jul 03, 2007 11:22 am

When you move code around between files, it's often a good idea to 'make clean' the whole project afterwards. Sometimes the old object files (the .o things) are still used, with the old symbols in them.

Another thing to watch for is that you might be compiling the same file twice. Wintermute's makefiles scan the SOURCES directories and add all the C files in it to the CFILES list (i.e., the list of files to compile). If there are double entries in CFILES, nothing you do inside the those C-files is going to matter.

The errors messages tell you which item(s) is offending to the compiler's eyes. Read the messages and use that information to find and fix the problem.

#133134 - dannyboy - Tue Jul 03, 2007 7:16 pm

Can you post your .h file that is causing the multiple definitions?

#133416 - M3d10n - Fri Jul 06, 2007 2:30 am

I have a C++ project using multiple .cpp and .h files shared among them without any problems. It's a port of an friend's Mac game using Objective C, Cocoa and OpenGL and the original source files' names and organization was kept almost intact for the port without problems.

There might be something wrong with your .h file or your makefile.

#133448 - HyperHacker - Fri Jul 06, 2007 7:12 am

k, here's the header file, yes it's a huge mess and the IPC messaging system sucks but hey, it's a work in progress. :-p
Code:
#ifndef _MAIN_H_
#define _MAIN_H_

//-----------------------#DEFINES-----------------------
#define MEMZERO(buf, len) memset(buf, 0, len)
#define KEY_DEBUG         BIT(14)

#define WIFI_FRAME_COUNT   (5*60) //how many frames to wait for a response to a command
#define MENU_STACK_MAX      32
#define OPTIONS_PER_PAGE   18 //number of menu options that can fit on the screen at once.

#define SCHANNEL_WAVEDUTY(n) (n << 24)
#define LESSEROF(x, y) (x < y ? x : y)
#define GREATEROF(x, y) (x > y ? x : y)

#define CONSOLEFLAGS (CONSOLE_32x32 | CONSOLE_BG(0) | CONSOLE_SCREENBASE(15) | CONSOLE_CHARBASE(0) | CONSOLE_GRADIENT)

#if ARM9 //these are only defined for ARM7
#define PM_SOUND_PWR      BIT(0)    // Power the sound hardware (needed to hear stuff in GBA mode too)
#define PM_SOUND_VOL      BIT(1)    // ?
#define PM_BACKLIGHT_BOTTOM   BIT(2)    // Enable the top backlight if set
#define PM_BACKLIGHT_TOP   BIT(3)    // Enable the bottom backlight if set
#define PM_SYSTEM_PWR      BIT(6)    // Turn the power *off* if set

#define GBA_BORDER_DATA      ((u16*)0x6020000) //VRAM address our borders will be stored at
#endif

//Copied from Moonshell
#define PM_NDSLITE_ADR (4)
#define PM_NDSLITE_ISLITE BIT(6)
#define PM_NDSLITE_BRIGHTNESS(x) ((x & 0x03)<<0)
#define PM_NDSLITE_BRIGHTNESS_MASK (PM_NDSLITE_BRIGHTNESS(3))

//Bits of system info in A9_INIT
#define SI_GBAONBOTTOM   0x00000001   //GBA screen is on bottom
#define SI_DSLITE      0x00000002   //Running on DS Lite

//Wifi control
#define WIFIPARAM_SYNC   0
#define WIFIPARAM_INIT   1
#define WIFIPARAM_STOP   2

//Debug
#define A7_STACK_DUMP_NUMWORDS 138 //Number of words that can be displayed in an ARM7 stack dump

//-----------------------LIBRARY INCLUDES-----------------------
#include <nds.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
//#include <cartreset_nolibfat.h>
//#include <cartreset.h>

#if ARM9
#include <stdarg.h>
#include <dswifi9.h>
#include <nds/arm9/libConsole.h>
#include <fat.h>
#include <sys/dir.h>
#include <unistd.h>

#else //ARM7
#include <dswifi7.h>

#endif //ARM7

//-----------------------STRUCT DEFINITIONS-----------------------
typedef struct {
   u32 A7MessageCount;      //ARM7 messages processed
   u32 A9MessageCount;      //ARM9 messages processed
   u32 A7FrameCount;      //Number of frames executed on ARM7
   u32 A9FrameCount;      //Number of frames executed on ARM9
   u32 TickCount;         //System run time in msec
   bool WifiEnabled;      //Whether wifi is enabled

   u32 ButtonsPressed;      //Buttons pressed this frame
   u32 ButtonsHeld;      //Buttons held >1 frame
   s16 TouchX, TouchY;      //Touch X/Y position
   s16 TouchZ1, TouchZ2;   //Touch Z panels
   u32 Temperature;      //System temperature

   union { //Current time
      struct {
         u8 Time_Command;
         u8 Time_Year;
         u8 Time_Month;
         u8 Time_Day;
         u8 Time_Incr;
         u8 Time_Hour;
         u8 Time_Minute;
         u8 Time_Second;
      };
      u8 TimeData[8];
   };

   u32 SysInfo;         //Information about system settings passed from ARM7 at bootup (any of SI_xxx).
} CustomIPCData;

static inline CustomIPCData volatile * getIPC2() {
   return (CustomIPCData volatile *)(IPC + sizeof(TransferRegion));
}

#define IPC2 getIPC2()


//Information for the Quickboot menu
typedef struct {
   char Name[30]; //Name to show in menu
   char Desc[129]; //Description to show in menu.
   char Section[129]; //Name of INI section.
} QuickbootData;


//Keys for KeyRepeat[]
typedef enum {
   KR_A = 0,
   KR_B,
   KR_SELECT,
   KR_START,
   KR_RIGHT,
   KR_LEFT,
   KR_UP,
   KR_DOWN,
   KR_R,
   KR_L,
   KR_X,
   KR_Y,
   NUM_KEYS
} KeyID;

//ARM7 messages
/* Messages are in this format: 1 byte message ID, 1 byte # of parameters,
2 bytes not used yet, then parameters (each 32 bits).
Return values are the parameters of an A7_RETURN or A9_RETURN message. */
typedef enum {
   A7_NULL,         //Dummy message, no parameters.
   A7_INIT,         //Used to pass some data from ARM9 at startup. Param1=Pointer to ARM7StackDump.
   A7_RETURN,         //Return value from a message; param1=message being responded to, others=return value.
   A7_CHECK,         //Used to check that ARM7 is still responding. Return value=anything; just returns a value to let ARM9 know it's still going.
   A7_ERROR,         //Notification that something bad happened; usually an invalid message was received. Param1=0 if invalid message.
   A7_GBAMODE,         //Reboot into GBA mode, no parameters.
   A7_SETPOWER,      //Change power settings; param1=0 to write, 1 to AND, 2 to OR, 3 to XOR; param2=bitflags. Note that System Power bit is reversed; 1=turn off.
   A7_GETPOWER,      //Retrieve power settings; no parameters, returns power bitflags. Note that System Power bit is 0 on Phat and 1 on Lite(?).
   A7_SETVOLUME,      //Set sound volume; param1=bits 0-6 set master sound volume, 7=1 to enable sound, 0 to disable.
   A7_GETVOLUME,      //Retrieve sound volume; return bits 0-6=master volume, 7=1 if enabled, 0 if disabled.
   A7_SETSOUND,      //Set flags for a sound channel; param1=channel (low 4 bits), param2=flags, param3=source, param4=length.
   A7_GETSOUNDFLAGS,   //Get flags for a sound channel; param1=channel (low 4 bits), return1=flags, return2=source, return3=length.
   A7_BOOTNDS,         //Enter wait loop to boot .nds file on GBAMP.
   A7_WIFICTRL,      //Wifi control messages; see below for params.

   //Higher-level system control commands
   A7_BACKLIGHT      //Set backlight brightness. Param1=Top light, Param2=Bottom light (-1=no change, 0=off, 1=on), Param3=Brightness (0-3 or -1 for no change, ignored if not DSLite)
} A7_MESSAGE;

/*
Bitmask for A7_SETSOUND and A7_GETSOUND:
evvvvvvv pppppppw wwffffff ffffffft

e=enable (1) or disable (0)
v=volume, 0=silent to 127=max
p=pan, 64=middle
w=wave duty, 0 to 6 (7=no sound)
f=frequqncy, 8 to 65528h
t=0 for standard mode, 1 for PSG (tone) mode (channels 8-13) or white noise (channel 14, 15)
Source and Length parameters are optional, and aren't used in PSG mode.


Parameters for A7_WIFICTRL:
WIFIPARAM_SYNC: Call Wifi_Sync().
WIFIPARAM_INIT: Pass Param2 to Wifi_Init(); turn on wifi hardware.
WIFIPARAM_STOP: Turn off wifi hardware.
*/


//ARM9 messages (same format as ARM7)
typedef enum {
   A9_NULL,         //Dummy message, no parameters.
   A9_INIT,         //ARM7 ready notification at startup, no parameters. IPC2->SysInfo is valid once this arrives.
   A9_RETURN,         //Return value from a message; param1=message being responded to, others=return value.
   A9_CHECK,         //Used to check that ARM9 is still responding. Return value=anything; just returns a value to let ARM7 know it's still going.
   A9_ERROR,         //Notification that something bad happened, usually an invalid message was received. Param1=0 if invalid message, 1-4 if invalid parameter..
   A9_FATALERROR,      //Notification that ARM7 has crashed. Param1=Error code, Param2=Stack pointer, Param3=Pointer to stack dump in main RAM since ARM9 can't read the real stack
   A9_WIFISYNC         //Signal that Wifi_Sync() needs to be called.
} A9_MESSAGE;


#if ARM9
enum Border {
   BD_SOLID = -1,
   BD_FILE,
   BD_RED,
   BD_GREEN,
   BD_BLUE,
   BD_YELLOW,
   BD_PURPLE,
   BD_MAX
};

//BootFile(), BootMenu() etc return codes
typedef enum {
   BE_UNKNOWN_ERROR = 0,
   BE_NOT_FOUND,         //File not found
   BE_FMT_NOT_SUPPORTED,   //File format not supported
   BE_CARD_NOT_SUPPORTED,   //Card not supported (also if e.g. .GBA file when no Slot-2 RAM)
   BE_INVALID_FILE,      //Corrupt or invalid file
   BE_NO_CARD,            //No DS card inserted
   BE_NULL_PTR,         //NULL pointer passed
   BE_INVALID_LOADER,      //Invalid loader specified
   BE_MAX               //Last item (not actually returned)
} BOOTERROR;
#endif //ARM9


//Loaders
typedef enum {
   LOAD_REBOOTLIB = 0,      //Rebootlib
   LOAD_GBAMP,            //GBAMP hack loader
   LOAD_MAX            //Last item
} LOADER;

typedef struct {
   char SSID[33];
   char WEPKey[16];
   bool AutoIP;
   u32 IPAddr;
   u32 SubnetMask;
   u32 Gateway;
   bool AutoDNS;
   u32 PrimaryDNS;
   u32 SecondaryDNS;
} APSettings;


//-----------------------OTHER HEADER INCLUDES-----------------------
//#include "..\..\general\memory.h"
//#include "..\..\general\_memory.h"
#include "reboot.h"
#if ARM7

#else //ARM9

#include "menu.h"
#endif //ARM9

//-----------------------CONSTANTS-----------------------
#if ARM7 //ndslib only declares this for ARM9 <_<
typedef enum KEYPAD_BITS {
  KEY_A      = BIT(0),  /*!< keypad A button */
  KEY_B      = BIT(1),  /*!< keypad B button */
  KEY_SELECT = BIT(2),  /*!< keypad SELECT button*/
  KEY_START  = BIT(3),  /*!< keypad START button*/
  KEY_RIGHT  = BIT(4),  /*!< keypad RIGHT button*/
  KEY_LEFT   = BIT(5),  /*!< keypad LEFT button*/
  KEY_UP     = BIT(6),  /*!< keypad UP button*/
  KEY_DOWN   = BIT(7),  /*!< keypad DOWN button*/
  KEY_R      = BIT(8),  /*!< RIGHT shoulder button*/
  KEY_L      = BIT(9),  /*!< LEFT shoulder button*/
  KEY_X      = BIT(10), /*!< keypad X button*/
  KEY_Y      = BIT(11), /*!< keypad Y button*/
  KEY_TOUCH  = BIT(12), /*!< touchscreen pendown*/
  KEY_LID    = BIT(13), /*!< lid state*/
} KEYPAD_BITS;

#else
const char* OnOff[] = {"Off", "On"};
const char* LightLevelStr[] = {"Low", "Med", "High", "Max"};
const char* MainScreenStr[] = {"Bottom", "Top"};
const char* BootError[] = {
   "Unknown error.",
   "File not found.",
   "File type not supported.",
   "Not supported on this card.",
   "Corrupt or invalid file.",
   "No card inserted.",
   "NULL pointer passed (bug!)",
   "Invalid loader specified."
};
const char* LoaderName[] = {"Rebootlib", "GBAMP"};

#endif //ARM9

//-----------------------GLOBAL VARS-----------------------
#if ARM9
volatile bool A7Init = false;

//System settings
s8 GBABorder = BD_SOLID;
char GBABorderFile[1024]; //Path to border file
u8 BorderR = 0, BorderG = 0, BorderB = 0; //Colours for solid border
bool TopLight = true, BottomLight = true; //Backlights on/off
s8 LightBright = 3; //Brightness level
bool EnableSound = true;
bool GBAROMOwner = true, GBASRAMOwner = true, NDSCardOwner = true; //false=ARM7 true=ARM9
bool MainScreenTop = true; //False = main screen on bottom
char SaveDownloadPath[1024]; //Path to save wireless downloads to; empty string = don't save
bool UseINI = true; //Whether settings in bootmenu.ini for the current game should override current ones

//Menu state
//Note: No checks are done to ensure the menu stack does not overflow, so ensure it doesn't.
u16 MenuStack[MENU_STACK_MAX];   //Array of which menus have been opened
u16 MenuSel[MENU_STACK_MAX];//Which option was selected on each
u16 MenuNumOptions[MENU_STACK_MAX]; //How many options are in the current menu
u8 MenuStackPos = 0;
s16 MenuOptionTouched = -1; //Which option was touched, -1 = none.
s8 TouchXTile = -1, TouchYTile = -1; //Tile coords touched, -1 = not touched.
QuickbootData* Quickboot = NULL;
u32 NumQuickboot = 0; //Number of Quickboot entries in INI

//Files
bool FATMounted = false;
char** Filename = NULL; //pointer to array of pointers to file names
u32 NumFiles = 0;
char CurrentDir[256];
FILE* File = NULL;

//Booting
LOADER DefaultLoader = LOAD_REBOOTLIB;

//Wifi
u8 MACAddress[6];
u8 WifiAPNum = 1; //0 = custom AP, 1-3 = firmware APs
APSettings WifiAP[4]; //WifiAPNum = index into this
s32 NumAPsFound = 0; //Number of APs found when scanning

//Keys
u16 KeysPressed = 0, KeysHeld = 0;
u16 KeyRepeatDelay = 256, KeyRepeatSpeed = 100; //milliseconds
u16 KeyRepeat[NUM_KEYS];
bool EnableKeyRepeat[NUM_KEYS];
char Password[17]; //Digit string: 0=A 1=B 2=Right 3=Left 4=Up 5=Down 6=L 7=R 8=X 9=Y
u32 PwdTries = 3; //Number of attempts allowed
bool PwdPowerOff = true; //After all attempts expired: true=power off, false=reject even correct password

//Startup message
char* StartMsg = NULL; //Text to show below password prompt
bool ForceStartMsg = false; //If true and no password, the message is shown anyway (press any key to continue).
bool ScrollStartMsg = false; //If true the message will scroll by on the menu screen.
u32 StartMsgDelay = 10; //How many frames to wait before advancing to next letter when scrolling

//Debug
bool DebugMode = false;
u32 ARM7StackDump[A7_STACK_DUMP_NUMWORDS]; //ARM7 will dump its stack into here on failure

#else //ARM7
u32 ASMHackery; //Global variable doing what should be done by a local one if I could figure out how >_>
u32* ARM7StackDump = 0; //Pointer to the real ARM7StackDump

#endif



//-----------------------FUNCTION PROTOTYPES-----------------------
#if ARM7
int main(int argc, char** argv);
void DoA7Message(A7_MESSAGE Message, u8 NumParams, u32 Param1, u32 Param2, u32 Param3, u32 Param4, bool FromA9);
void SendA9Message(A9_MESSAGE Message, u8 NumParams, u32 Param1, u32 Param2, u32 Param3, u32 Param4);
void VBlankInterrupt();
void Timer3Interrupt();
void WifiInterrupt();
void syncRTC();
bool A7InitWifi(u32 A9Param);
void _A7WifiSync();
void FatalError(u32 Code);

#elif ARM9
int main(int argc, char** argv);
void DrawMenu(u32 ID, u32 Selected);
void EnterMenu(u32 ID);
void PasswordPrompt();
bool ReadConfigFile(char* Section);
s32 ListDirectory(char* Dir);
s32 filenamecmpi(char* str1, char* str2);
void ApplySystemSettings(bool NoUnmount);
void CheckMessages();
void DoA9Message(A9_MESSAGE Message, u8 NumParams, u32 Param1, u32 Param2, u32 Param3, u32 Param4, bool FromA7);
void SendA7Message(A7_MESSAGE Message, u8 NumParams, u32 Param1, u32 Param2, u32 Param3, u32 Param4);
void VBlankInterrupt();
bool InitWifi();
bool StopWifi();
void _A9WifiSync();

//boot.c
BOOTERROR BootFile(LOADER Loader, char* File);
bool IsLoaderSupported(LOADER Loader);
BOOTERROR BootMenu();
void BootGBAMode();
BOOTERROR BootDSCard();
void PowerOff();

#endif //not ARM7

#endif //_MAIN_H_


The makefile is just the standard one, except I've added a bit to automatically apply a DLDI patch and run WMB.
_________________
I'm a PSP hacker now, but I still <3 DS.

#133474 - mml - Fri Jul 06, 2007 10:52 am

Code:
const char* OnOff[] = {"Off", "On"};
...
const char* LoaderName[] = {"Rebootlib", "GBAMP"};


and everything from

Code:
//-----------------------GLOBAL VARS-----------------------


down to

Code:
//-----------------------FUNCTION PROTOTYPES-----------------------


should not be in your .h file. These are variable definitions; variables may only be defined once. This is why when you include this .h from multiple source files, the compiler whinges about "multiple definitions"

You can have multiple declarations of a variable, but not multiple definitions. Hint: the solution involves the keyword extern as advised by someone earlier. :)

#133542 - HyperHacker - Sat Jul 07, 2007 12:19 am

Where should they be then?
_________________
I'm a PSP hacker now, but I still <3 DS.

#133546 - masscat - Sat Jul 07, 2007 12:59 am

If you want to make a variable available globally then define the instance of the variable (telling the compiler to assign it memory and give it a name) in some C source file outside of any functions (eg main.c). This should only get compiled once and therefore there will only be a single definition of the variable:

Code:
...
some code
...
int some_global_var;
...
...
some more code
...
...


Then declare the existence of the variable in a header file using the 'extern' keyword.

Code:
extern int some_global_var;

This tells the compiler the size and type of 'some_global_var' allowing it to be used within the code that includes the header file but indicates that it is defined elsewhere (in main.c in this case) and the actual instance will be picked up during linking.


Now a whole other discussion, should you be using global data or not.
I personally strongly dislike global data. It can make code very hard to understand and maintain (even to the original author) as it is not obvious where and in what order a variable's value can change. Only ever use it in very well defined circumstances, i.e. you know (and comment) exact why and how the variable will change and this behaviour will not change in the future.

#133547 - HyperHacker - Sat Jul 07, 2007 1:15 am

Yeah, a lot of this code is subject to change. Merging some things into structs and classes and whatnot. Come to think of it at least one of those isn't even used anymore... this is what happens when you base something on old code. :-S

Anyway extern fixed it (thanks), but I have another question: how do I access local variables in inline ASM? The compiler must be mangling their names or something because just referencing them by name doesn't work as it does with globals.
_________________
I'm a PSP hacker now, but I still <3 DS.

#133687 - masscat - Sun Jul 08, 2007 12:29 am

Here is a gcc inline assembly howto, i386 based but gives the syntax and principles. And another one.
You can find some examples of ARM inline assembly in the gdb debug stub code.
Only use assembly for fun (in a strange sense of the word), when need to access some specific functions of the processor/platform (eg cache flushing) or when you really need to optimise something and you know you can do it better than the compiler.

#133704 - HyperHacker - Sun Jul 08, 2007 1:11 am

Thanks. I see this note in the first one:
Code:
int a=10, b;
asm ("movl %1, %%eax;
   movl %%eax, %0;"
   :"=r"(b)        /* output */
   :"r"(a)         /* input */
   :"%eax"         /* clobbered register */
);

When I tried this, I got "undefined reference to r4", even though there was no "r4" to be found. I don't still have the exact code that caused it, but I'll try to reproduce it after dinner.

All I'm trying to do now is get the stack pointer to perform a dump, but I'll probably need to do other things inline later, so I may as well know how.
_________________
I'm a PSP hacker now, but I still <3 DS.

#133709 - masscat - Sun Jul 08, 2007 1:43 am

The first link is for inline i386 assembly, only the syntax and concepts are applicable. The second link gives ARM assembly examples.
Here is the code to get the stack pointer (I think):
Code:
uint32_t getStackPtr( void) {
  uint32_t stack_ptr;

  asm ( "mov %0, sp"
        : "=r" (stack_ptr)
        :
        );

  return stack_ptr;
}

#133844 - HyperHacker - Mon Jul 09, 2007 6:16 am

Yeah, that got it. The r4 thing was just caused by a dumb typo. <_< Thanks.
_________________
I'm a PSP hacker now, but I still <3 DS.

#133847 - HyperHacker - Mon Jul 09, 2007 7:11 am

I spoke too soon. Somehow, this is enough to corrupt the stack:
Code:
u32 foo;
__asm (
      ".arm\n"
      "mov %0, sp\n"
: "=r" (foo));


I was able to get it not to cause corruption like so:
Code:
u32 foo;
u32* bar = &foo;
__asm (
      ".arm\n"
      "str sp, [%0]\n"
: "=r" (bar);

But the result is obviously wrong (0x20). :-( The addresses displayed by the default exception handler don't help much either; addr2line tells me they're in my VBlank interrupt handler (even when interrupts are disabled) on lines that either wouldn't be getting executed or don't even have anything on them.

The effects vary from printing a load of gibberish instead of the stack pointer to freezing to data abort. The first especially tells me the stack or possibly registers are getting stomped on. Using a global variable doesn't help, so it's not like it's storing to the wrong place. I wonder if the compiler isn't doing something silly like optimizing the variable out entirely because it doesn't realize the ASM is using it (even though it's listed as an output). >_>

As for debugging it in an emulator, none of them even get that far. They don't seem to support IPC FIFO. O_o
_________________
I'm a PSP hacker now, but I still <3 DS.