A few months ago I received the code below from WinterMute, who was kind enough to show me a fully functioning app launcher, and whose code, for the most part works A-OK. However, ever since libogc 1.8.10 was released, the code somehow seems to fail to send the appropiate command-line arguments specified in the call to runDOL().
The thing is, it doesn't always do that. It is entirely random. There was an instance where I had to run the launcher 5 times before the app being launched got the command-line arguments right.
It was until very recently ago that I learned the app launcher actually needs to run in non-allocated memory, in order to work as it should. The memory address for that is specified directly in the project makefile.
Also, today, I've come to realize that the address where command-line arguments are copied to the program being launched has also a fixed memory address; this one also seems to be in non-allocated memory (though I'm not entirely sure).
My launcher app, today, measures 332KB (340.384 bytes). It has grown quite a bit since WinterMute gave me that code. I'm worried that the fixed memory addresses currently specified in the program are no longer right, either because my app has become larger and larger, or because something in libogc (or the toolchain itself) has changed significatively, enough to make these memory addresses no longer correct.
I also can say, honestly, I have no idea why do we choose these memory address values, apart from this "these are outside allocated memory" explanation.
So, guys: Could these memory addresses be the problem causing that the launched apps do not get command-line arguments all the time? And if so, what is/are the rule(s) that define how these memory addresses should be specified?
----------------------
This is rundol.c : Note: please don't use this. Use instead the code WinterMute posted below.
Code: Select all
#include <string.h>
#include <gccore.h>
#include <ogc/lwp_threads.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fat.h>
#include <stdio.h>
typedef struct _dol_header_t {
u32 textFileAddress[7];
u32 dataFileAddress[11];
u32 textMemAddress[7];
u32 dataMemAddress[11];
u32 textSize[7];
u32 dataSize[11];
u32 bssMemAddress;
u32 bssSize;
u32 entry;
} _dol_header;
static _dol_header dolHeader;
typedef void (*entrypoint) (void);
char *argvBuffer = (char *)0x81708000;
extern char _start[];
bool checkAddress(u32 start, u32 size ) {
u32 upperLimit = (u32)SYS_GetArena1Hi();
u32 lowerLimit = (u32)_start;
if ( start > lowerLimit && start < upperLimit ) return false;
if ( (start + size ) > lowerLimit && ( start + size ) < upperLimit ) return false;
return true;
}
bool loadSections( int number, u32 fileAddress[], u32 memAddress[], u32 size[], FILE* dolFile ) {
int i;
for ( i = 0; i < 7; i++ ) {
if ( fileAddress[i] != 0 ) {
if ( !checkAddress( memAddress[i], size[i] ) ) return false;
fseek( dolFile, fileAddress[i], SEEK_SET );
if ( size[i] != fread( (void *)memAddress[i], 1, size[i], dolFile) ) return false;
DCFlushRange ((void *) memAddress[i], size[i]);
}
}
return true;
}
void setArgv (int argc, const char **argv, char *argStart, struct __argv *dol_argv) {
char* argData;
int argSize;
const char* argChar;
// Give arguments to dol
argData = (char*)argStart;
argSize = 0;
for (; argc > 0 && *argv; ++argv, --argc) {
for (argChar = *argv; *argChar != 0; ++argChar, ++argSize) {
*(argData++) = *argChar;
}
*(argData++) = 0;
++argSize;
}
*(argData++) = 0;
++argSize;
dol_argv->argvMagic = ARGV_MAGIC;
dol_argv->commandLine = argStart;
dol_argv->length = argSize;
DCFlushRange ((void *) argStart, argSize);
}
bool runDOL (const char* filename, int argc, const char** argv) {
struct stat st;
char filePath[MAXPATHLEN * 2];
int pathLen;
const char* args[1];
if (stat (filename, &st) < 0) {
return false;
}
if (argc <= 0 || !argv) {
// Construct a command line if we weren't supplied with one
if (!getcwd (filePath, MAXPATHLEN)) {
return false;
}
pathLen = strlen (filePath);
strcpy (filePath + pathLen, filename);
args[0] = filePath;
argv = args;
argc = 1;
}
//printf("file size is %lld\n", st.st_size);
FILE *dolFile = fopen(filename,"rb");
if ( dolFile == NULL ) return false;
u32 *entryPoint;
if ( sizeof(dolHeader) == fread(&dolHeader,1, sizeof(dolHeader), dolFile) ) {
if ( loadSections( 7, dolHeader.textFileAddress, dolHeader.textMemAddress, dolHeader.textSize, dolFile ) ) {
if ( loadSections( 11, dolHeader.dataFileAddress, dolHeader.dataMemAddress, dolHeader.dataSize, dolFile ) ) {
fclose(dolFile);
dolFile = NULL;
entryPoint = (u32*)dolHeader.entry;
if ( entryPoint[1] == ARGV_MAGIC ) {
setArgv( argc, argv, argvBuffer, (struct __argv*)&entryPoint[2]);
}
SYS_ResetSystem(SYS_SHUTDOWN,0,0);
__lwp_thread_stopmultitasking((entrypoint)entryPoint);
}
}
}
if(dolFile != NULL) fclose(dolFile);
return false;
}
And this is the section of the makefile that specifies the fixed memory address to set the app launcher:
Code: Select all
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE)
CXXFLAGS = $(CFLAGS)
LDFLAGS = -s -g $(MACHDEP) -Wl,--section-start,.init=0x81200000 -Wl,-Map,$(notdir $@).map