Help with rundol launcher code...

support for the powerpc toolchain
Post Reply
User avatar
Izhido
Posts: 107
Joined: Fri Oct 19, 2007 10:57 pm
Location: Costa Rica
Contact:

Help with rundol launcher code...

Post by Izhido » Mon May 14, 2012 3:12 am

Guys, I need a little help here, to actually understand what is wrong with my launching app.

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


WinterMute
Site Admin
Posts: 1858
Joined: Tue Aug 09, 2005 3:21 am
Location: UK
Contact:

Re: Help with rundol launcher code...

Post by WinterMute » Tue May 15, 2012 1:30 am

Heh, I did tell you it was old code when I gave it to you :p This predated HBC and was originally going to be an sdloader replacement for gamecube but I never really found the time to do much with it.

0x81708000 used to be above __Arena1Hi so there was no chance of it being overwritten but really the argv buffer should just have been a static array. I've put the latest code on github @ https://github.com/WinterMute/dolloader so you can just grab that. I'm not sure if you got the code that could handle argv files or not.
Help keep devkitPro toolchains free, Donate today

Personal Blog

User avatar
Izhido
Posts: 107
Joined: Fri Oct 19, 2007 10:57 pm
Location: Costa Rica
Contact:

Re: Help with rundol launcher code...

Post by Izhido » Tue May 15, 2012 5:22 am

Thanks! The static array did the trick, apparently. Still need to run a few more tests, but so far it seems to work.

On a related note, I was wondering... the code you posted opens the .dol file and reads it, but never closes it. Is that on purpose?

WinterMute
Site Admin
Posts: 1858
Joined: Tue Aug 09, 2005 3:21 am
Location: UK
Contact:

Re: Help with rundol launcher code...

Post by WinterMute » Tue May 15, 2012 10:14 am

The file handle does get closed if the launch failed, there's no particular reason to close it if launching succeeds - the whole system is reset before control reaches the launched application ( don't forget this isn't a multitasking OS )

I've added an extra close before launching anyway just for the sake of consistency and avoiding silly questions :p

I also noticed that the argv struct itself isn't flushed so I added that in the latest code too.
Help keep devkitPro toolchains free, Donate today

Personal Blog

Post Reply

Who is online

Users browsing this forum: No registered users and 30 guests