Operations performed by _start()
Operations performed by _start()
Can anyone tell me (or point me at the code that shows) what operations are performed by the _start() function generated by the toolchain?
In attempting to debug the v2.0 FW beta EBOOT loader for EBOOTs that currently don't work, it's looking like the problem lies with the entry code being generated by the toolchain.
So, I'm trying to work out whether there are any problematic operations (e.g. kernel-mode calls) going on in that code, that might be causing a crash during initialisation.
I've looked around the SVN source trying to find the relevant source code, and I'm working on getting a decent disassembly of the object code, but so far without any luck. A high-level overview of what that code is doing would be really helpful.
Thanks in advance.
In attempting to debug the v2.0 FW beta EBOOT loader for EBOOTs that currently don't work, it's looking like the problem lies with the entry code being generated by the toolchain.
So, I'm trying to work out whether there are any problematic operations (e.g. kernel-mode calls) going on in that code, that might be causing a crash during initialisation.
I've looked around the SVN source trying to find the relevant source code, and I'm working on getting a decent disassembly of the object code, but so far without any luck. A high-level overview of what that code is doing would be really helpful.
Thanks in advance.
You can usually find _start in the crt0 file.
http://svn.pspdev.org/filedetails.php?r ... rev=0&sc=0
Code: Select all
/**
* Startup thread
*
* Creates the main program thread based on variables defined by the program.
*
* @param args - Size (in bytes) of arguments passed to the program by the kernel.
* @param argp - Pointer to arguments passed by the kernel.
*/
int _start(SceSize args, void *argp)
{
void (*_main_func)(SceSize args, void *argp) = _main;
void (*_init_func)(void) = _init;
if ((&module_info != NULL) && (module_info.modattribute & 0x1000)) {
/* If we're running in kernel mode, the addresses of our _main() thread
and _init() function must also reside in kernel mode. */
_main_func = (void *) ((u32) _main_func | 0x80000000);
_init_func = (void *) ((u32) _init_func | 0x80000000);
}
/* Call _init() here, because an app may have code that needs to run in
kernel mode, but want their main() thread to run in user mode. If they
define "constructors" they can do any kernel mode initialization here
before their app is switched. */
_init_func();
if (&sce_newlib_nocreate_thread_in_start != NULL) {
/* The program does not want main() to be run in a seperate thread. */
_main_func(args, argp);
return 1;
}
int priority = DEFAULT_THREAD_PRIORITY;
unsigned int attribute = DEFAULT_THREAD_ATTRIBUTE;
unsigned int stackSize = DEFAULT_THREAD_STACK_KB_SIZE * 1024;
if (&sce_newlib_priority != NULL) {
priority = sce_newlib_priority;
}
if (&sce_newlib_attribute != NULL) {
attribute = sce_newlib_attribute;
}
if (&sce_newlib_stack_kb_size != NULL) {
stackSize = sce_newlib_stack_kb_size * 1024;
}
/* Does the _main() thread belong to the User, VSH, or USB/WLAN APIs? */
if (attribute & (PSP_THREAD_ATTR_USER | PSP_THREAD_ATTR_USBWLAN | PSP_THREAD_ATTR_VSH)) {
/* Remove the kernel mode addressing from the pointer to _main(). */
_main_func = (void *) ((u32) _main_func & 0x7fffffff);
}
SceUID thid;
thid = sceKernelCreateThread("user_main", (void *) _main_func, priority, stackSize, attribute, 0);
sceKernelStartThread(thid, args, argp);
return 0;
}
And or I missed something or the args parsing is not done..
I'm wrong ?
I'm wrong ?
- TiTAN Art Division -
http://www.titandemo.org
http://www.titandemo.org
Well, some good news...
It does indeed seem (from examining disassembly etc) that the problem loading most existing homebrew into v2.0 is due to the way the main thread is created by this start() function.
By messing around with the module and thread options compiled into some of the SDK samples, I've been able to compile all the samples I've tested so far such that they now load under v2.0 (using a slightly-modified loader).
It's a little early to announce any details, and ideally I want to find some way to patch existing binaries without requiring recompilation.
But things are looking very promising in terms of being able to run just about any existing user-mode homebrew (which does seem to be the majority) on v2.0.
It does indeed seem (from examining disassembly etc) that the problem loading most existing homebrew into v2.0 is due to the way the main thread is created by this start() function.
By messing around with the module and thread options compiled into some of the SDK samples, I've been able to compile all the samples I've tested so far such that they now load under v2.0 (using a slightly-modified loader).
It's a little early to announce any details, and ideally I want to find some way to patch existing binaries without requiring recompilation.
But things are looking very promising in terms of being able to run just about any existing user-mode homebrew (which does seem to be the majority) on v2.0.
What problem? The PSPSDK crt0 works fine for apps that run in usermode only, it doesn't require kernel mode (that's why it's all hacked up).Fanjita wrote:It does indeed seem (from examining disassembly etc) that the problem loading most existing homebrew into v2.0 is due to the way the main thread is created by this start() function.
If you can't launch a pure user-only PSPSDK application then the problem is in the loader. Your loader should be able to check the kernel bit in the module info and reject those from working anyway.
"The problem" is just that most homebrew crashes immediately after starting under the current loader - even for most user-mode apps.
If I mess around with the startup behaviour being asked for by the app, then I can overcome that (for kernel mode applications).
(I suspect it is something about the loader's behaviour, which is why I'm hopeful I can fix it within the loader, without requiring recompilation of any apps).
If I mess around with the startup behaviour being asked for by the app, then I can overcome that (for kernel mode applications).
(I suspect it is something about the loader's behaviour, which is why I'm hopeful I can fix it within the loader, without requiring recompilation of any apps).
I still don't follow. You say "I can overcome that (for kernel mode applications)", so does that mean that the PSPSDK samples that don't require kernel mode work fine? If not, what is it you think is happening in _start() that causes them to break?
_start() assumes that the runtime environment is the same used on 1.0 and 1.5. Your loader has to somehow get the exploit environment into that environment if user-only apps will work as is.
Besides patching, I don't see how you can get out of recompiling any app that starts up in kernel mode by default, since the address range code in _start() will kill you right away...
_start() assumes that the runtime environment is the same used on 1.0 and 1.5. Your loader has to somehow get the exploit environment into that environment if user-only apps will work as is.
Besides patching, I don't see how you can get out of recompiling any app that starts up in kernel mode by default, since the address range code in _start() will kill you right away...
Sorry, that was a typo, it should have said "I can work around that for user-mode applications".
In terms of environment, it seems that the exploit environment isn't so different to the 1.0/1.5 runtime environment - the only issue does seem to be the lack of kernel mode access.
To be clear - I very much doubt I can get kernel-mode apps working (although it may be possible to hack some apps around with patching, I suppose, but certainly not the general case). But I'm very confident that user-mode apps can work fine.
Anyway - back to the coding...
In terms of environment, it seems that the exploit environment isn't so different to the 1.0/1.5 runtime environment - the only issue does seem to be the lack of kernel mode access.
To be clear - I very much doubt I can get kernel-mode apps working (although it may be possible to hack some apps around with patching, I suppose, but certainly not the general case). But I'm very confident that user-mode apps can work fine.
Anyway - back to the coding...
Heh, it turned out that the main problem was that the loader wasn't supplying anything in $ra when it called into the app - so anything that created a "user_main" thread, and then exited (the majority of PSPSDK apps, I'd guess, since it's the default) were ending up heading off into the unknown during initialisation.
I've now released my version of the loader at my website, it seems to work pretty well with most user-mode homebrew that I've tried.
I've now released my version of the loader at my website, it seems to work pretty well with most user-mode homebrew that I've tried.
:)
I'm still trying to decide whether or not I'm proud of my hack to get a valid address into $RA... Unless I'm missing something, there's no convenient "JRAL" opcode, so to jump to a dynamic address (with "JR") I need to fake up my own $RA value beforehand.
Eventually I did it with:
(EBOOT entry point is in $A2):
JAL straightback
NOP
ADDIU $RA, $RA, 0x18
JR $A2
NOP
NOP
NOP
NOP
NOP
SYSCALL nnnn (sleep thread)
straightback:
JR $RA
NOP
I'm still trying to decide whether or not I'm proud of my hack to get a valid address into $RA... Unless I'm missing something, there's no convenient "JRAL" opcode, so to jump to a dynamic address (with "JR") I need to fake up my own $RA value beforehand.
Eventually I did it with:
(EBOOT entry point is in $A2):
JAL straightback
NOP
ADDIU $RA, $RA, 0x18
JR $A2
NOP
NOP
NOP
NOP
NOP
SYSCALL nnnn (sleep thread)
straightback:
JR $RA
NOP
wow, nice to see you actually came this far, and did not give up like me :)
regarding your code - looks ok, but how about this:
(I know, I'm an asm masochist, and have to find every "wasted" cycle ;))
and what about the NOPs in you code? were there problems without them?
EDIT:
wait a sec JALR didn't work? or did you try "JRAL" (like you have written) instead "JALR $RA, $A2"
regarding your code - looks ok, but how about this:
(I know, I'm an asm masochist, and have to find every "wasted" cycle ;))
Code: Select all
JAL somelabel
NOP
somelabel:
JR $A2
ADDIU $RA, $RA, 8
SYSCALL nnnn (sleep thread)
EDIT:
wait a sec JALR didn't work? or did you try "JRAL" (like you have written) instead "JALR $RA, $A2"
infj
Ah! JALR - didn't try that, and JRAL was rejected by gas.
I couldn't find mention of JALR anywhere, so I assumed that it must not exist - excellent, I'll just update the code to use the far-more-sensible JALR.
Thanks!
P.S. The NOPs were just because I was being lazy and couldn't be bothered working out the right offset exactly :)
I couldn't find mention of JALR anywhere, so I assumed that it must not exist - excellent, I'll just update the code to use the far-more-sensible JALR.
Thanks!
P.S. The NOPs were just because I was being lazy and couldn't be bothered working out the right offset exactly :)