Operations performed by _start()

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Operations performed by _start()

Post by Fanjita »

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.
ooPo
Site Admin
Posts: 2023
Joined: Sat Jan 17, 2004 9:56 am
Location: Canada
Contact:

Post by ooPo »

You can usually find _start in the crt0 file.

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;
}
http://svn.pspdev.org/filedetails.php?r ... rev=0&sc=0
User avatar
Shazz
Posts: 244
Joined: Tue Aug 31, 2004 11:42 pm
Location: Somewhere over the rainbow
Contact:

Post by Shazz »

And or I missed something or the args parsing is not done..

I'm wrong ?
- TiTAN Art Division -
http://www.titandemo.org
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

Excellent, thanks.

It does look like there's a fair bit there worth investigating.
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

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.
mrbrown
Site Admin
Posts: 1537
Joined: Sat Jan 17, 2004 11:24 am

Post by mrbrown »

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.
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).

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.
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

"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).
mrbrown
Site Admin
Posts: 1537
Joined: Sat Jan 17, 2004 11:24 am

Post by mrbrown »

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...
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

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...
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

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.
mrbrown
Site Admin
Posts: 1537
Joined: Sat Jan 17, 2004 11:24 am

Post by mrbrown »

Fanjita, you are the man :).
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

:)

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
User avatar
Saotome
Posts: 182
Joined: Sat Apr 03, 2004 3:45 am

Post by Saotome »

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 ;))

Code: Select all

JAL somelabel
NOP
somelabel: 
JR $A2 
ADDIU $RA, $RA, 8
SYSCALL nnnn (sleep thread) 
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"
infj
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

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 :)
Post Reply