Problems with PRX exports using C++

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

Moderators: cheriff, TyRaNiD

Post Reply
Anissian
Posts: 16
Joined: Fri Jan 26, 2007 8:40 pm

Problems with PRX exports using C++

Post by Anissian »

All,

I recently started PSP development using C++ and I have a couple of questions. I apologize in advance if they are answered or RTFM, I goggled and searched in the forums, but without success.

a) first, regarding PRX exports. psp-build-exports generates a valid C file, but g++ chokes if we try to consider it as C++ file. For the time being, I want to export only either global functions or static member functions, so I need to solve name mangling issues only. I have done the following:

Makefile

Code: Select all

%.cc: %.exp
             psp-build-exports -b $< > $@

LINK.cc=$&#40;LINK.c&#41;

Code: Select all

--- psp-build-exports.c.old	2007-01-26 12&#58;12&#58;09.000000000 +0100
+++ psp-build-exports.c	2007-01-26 12&#58;29&#58;36.000000000 +0100
@@ -335,7 +335,11 @@
 	pExp = pHead;
 	while&#40;pExp != NULL&#41;
 	&#123;
+		fprintf&#40;stdout, "#if defined &#40;__STDC__&#41; || defined&#40;__cplusplus&#41;\n"&#41;;
+		fprintf&#40;stdout, "extern char %s;\n", pExp->name&#41;;
+		fprintf&#40;stdout, "#else\n"&#41;;
 		fprintf&#40;stdout, "void extern %s;\n", pExp->name&#41;;
+		fprintf&#40;stdout, "#endif\n"&#41;;
 		pExp = pExp->pNext;
 	&#125;
 &#125;
@@ -399,14 +403,14 @@
 	&#123;
 		if&#40;strcmp&#40;pLib->name, SYSTEM_LIB_NAME&#41; == 0&#41;
 		&#123;
-			fprintf&#40;stdout, "\t&#123; NULL, "&#41;;
+			fprintf&#40;stdout, "\t&#123; &#40;const char*&#41;NULL, "&#41;;
 		&#125;
 		else
 		&#123;
-			fprintf&#40;stdout, "\t&#123; \"%s\", ", pLib->name&#41;;
+			fprintf&#40;stdout, "\t&#123; &#40;const char*&#41;\"%s\", ", pLib->name&#41;;
 		&#125;
 
-		fprintf&#40;stdout, "0x%04X, 0x%04X, 4, %d, %d, &__%s_exports &#125;,\n", pLib->ver, pLib->attr, 
+		fprintf&#40;stdout, "0x%04X, 0x%04X, 4, %d, %d, &#40;void*&#41;&__%s_exports &#125;,\n", pLib->ver, pLib->attr, 
 				pLib->varCount, pLib->funcCount, pLib->name&#41;;
 
 		pLib = pLib->pNext
I don't know how to generate the extern symbols in valid c++ without knowing the variable type or the function prototype. the "extern char" is a dirty hack, but there may be alignment issues. Is there a more elegant way of doing this?


b) what is the argp argument of s SceKernelThreadEntry? is there a way to make it a user pointer so a given thread object or task can be passed? Apparently there seems to be no way to pass a user pointer to sceKernelCreateThread

Code: Select all


namespace psp &#123;

// Task is a template parameter with a class that 
// implements i_runnable &#40;e.g. has a run&#40;&#41; method&#41;
   
   template<typename Task>
   class thread 
   &#123;
           static int func &#40;SceSize n, void* p&#41;
           &#123;
                 static_cast<Task*>&#40;p&#41;->run&#40;&#41;;
                 ....
            &#125;

 ...
           int create &#40;...&#41;
           &#123;
                  m_thid = &#58;&#58;sceKernelCreateThread &#40;m_name.c_str&#40;&#41;, thread&#58;&#58;func...&#41;
                
          &#125;
    &#125;

Many thanks in advance
MrMr[iCE]
Posts: 43
Joined: Mon Oct 03, 2005 4:55 pm

Re: Problems with PRX exports using C++

Post by MrMr[iCE] »

Anissian wrote: b) what is the argp argument of s SceKernelThreadEntry? is there a way to make it a user pointer so a given thread object or task can be passed? Apparently there seems to be no way to pass a user pointer to sceKernelCreateThread
no, you cant pass user data in sceKernelCreateThread, but you can in sceKernelStartThread:

Code: Select all

/**
 * Start a created thread
 *
 * @param thid - Thread id from sceKernelCreateThread
 * @param arglen - Length of the data pointed to by argp, in bytes
 * @param argp - Pointer to the arguments.
 */
int sceKernelStartThread&#40;SceUID thid, SceSize arglen, void *argp&#41;;
TyRaNiD
Posts: 907
Joined: Sun Jan 18, 2004 12:23 am

Post by TyRaNiD »

Simplest option is just export then as 'extern "C"' :) Exporting real classes is fraught with problems and it probably isn't worth the effort.

If you _really_ have to have C++ mangled names then your idea will only work for the export table itself not necessarily for the stub files you then need to link these functions to something else.

What I would do is this, compile your C++ bits you need to export into an object file, then do something like:
psp-nm mycode.o | grep 'T _Z.*' | awk '{ print "PSP_EXPORT_FUNC(" $3 ")" }'
which will emit the function exports which you can copy into an export file.
white rabbit
Posts: 60
Joined: Wed Jul 06, 2005 7:03 pm

Post by white rabbit »

Hmm, I'm getting nowhere fast with this...

Code: Select all

$ psp-g++ -G0 -O2 -Wall -c -o foo.o foo.cpp -I$PSPSDK/include/
$ psp-nm | grep 'T _Z.*' | awk '&#123; print "PSP_EXPORT_FUNC&#40;" $3 "&#41;" &#125;'
I stick these into exports.exp

Code: Select all

$ psp-build-exports -b exports.exp > exports.cpp
I edit exports.cpp to make it type safe(r) - nasty hack as mentioned above. I've tried using the 'extern "C"' bit, but that doesn't seem to make any difference.

Code: Select all

$ psp-g++ -G0 -O2 -Wall -c -o exports.o exports.cpp -I$PSPSDK/include/
Everyting is ok so far :)

So now I try to link it, thus...

Code: Select all

$ psp-g++ -o foo.elf -Wall -O2 -G0 foo.o main.o export.o -L /usr/local/pspdev_precomp/pspdev/psp/sdk/lib/ -L /usr/local/pspdev_precomp/pspdev/psp/lib/ -specs=/usr/local/pspdev_precomp/pspdev/psp/sdk/lib/prxspecs -Wl,-q,-T/usr/local/pspdev_precomp/pspdev/psp/sdk/lib/linkfile.prx -lpspkernel
and it's not happy :(

Code: Select all

/usr/local/pspdev_precomp/pspdev/bin/../lib/gcc/psp/4.0.2/../../../../psp/lib/cr
t0_prx.o&#58; In function `_main'&#58;
/home/loser/newtoolchain/pspsdk/src/startup/crt0_prx.c&#58;88&#58; undefined reference t
o `atexit'
/home/loser/newtoolchain/pspsdk/src/startup/crt0_prx.c&#58;94&#58; undefined reference t
o `exit'
collect2&#58; ld returned 1 exit status
If I try -lstdc++ then I get the same issues. In fact the only library that can make any difference is -lpspc BUT that throws up new problems (as I'd expect using c++).

So... Am I being a big moron?
TyRaNiD
Posts: 907
Joined: Sun Jan 18, 2004 12:23 am

Post by TyRaNiD »

Well for a start once you have the mangled names dont stick it in a cpp file , Else you are going to get potentially menagled names for mangled names ;)

Of course your real issue is you are trying no doubt to make a kernel module or at least disabled the use of newlib. I really wouldn't use c++ in a kernel module anyway :)
raf
Posts: 57
Joined: Thu Oct 13, 2005 7:38 am

Re: Problems with PRX exports using C++

Post by raf »

Excuse me if I'm confusing your problem; but on PSPRadio (which is C++ and has C++ prx plugins), all I do is:

Code: Select all

psp-build-exports -s UI_Exports.exp
(which has:

Code: Select all

       PSP_EXPORT_START&#40;PSPRadio_UI, 0, 0x0001&#41;
                PSP_EXPORT_FUNC_HASH&#40;getModuleInfo&#41;
                PSP_EXPORT_FUNC_HASH&#40;ModuleStartUI&#41;
        PSP_EXPORT_END
)

This generates a PSPRadio_UI.S file, so in PSPRadio's Makefile, I have PSPRadio_UI.o as one of the defined objects.. And that's it....

Then, in the header file (shared), I define:
extern "C"
{
/** In UI PRX */
void* getModuleInfo(void);
IPSPRadio_UI *ModuleStartUI();
}

Where IPSPRadio_UI is the class I use as interface. But you can define the export to be a wrapper for the method you want to access?

Raf.
Anissian
Posts: 16
Joined: Fri Jan 26, 2007 8:40 pm

Re: Problems with PRX exports using C++

Post by Anissian »

raf wrote:(...) all I do is:

Code: Select all

psp-build-exports -s UI_Exports.exp
This generates a PSPRadio_UI.S file, so in PSPRadio's Makefile, I have PSPRadio_UI.o as one of the defined objects.. And that's it....
Raf,

Indeed, this works, although the original post was referring to the fact that if you generate a .cc using build exports, the generated .cc is not c++ type safe so g++ aborts (thus the fast-hack / diff-patch)... plus the c++ name mangling messing up.

On the other hand, yes, this is basically what I end up doing (which matches Tyranid suggestion): use extern C wrappers and factory idioms to access c++ (static) class methods. The module caller holds references to class instances, etc.

Where IPSPRadio_UI is the class I use as interface. But you can define the export to be a wrapper for the method you want to access?
Raf.
yes, as long as it is ExternC'ed and so on to avoid name mangling problems, it works. Although this does not solve the underlying problem of exporting C++ functions (albeit static class members or non-class members) without messing around with name mangling. I guess it can be done/automated, but previous suggestions are fine for me :)

Thanks for sharing,
raf
Posts: 57
Joined: Thu Oct 13, 2005 7:38 am

Re: Problems with PRX exports using C++

Post by raf »

Anissan,

When I read this:
Anissian wrote:(...)
For the time being, I want to export only either global functions or static member functions, so I need to solve name mangling issues only.
I thought that what I did could be sufficient to solve that problem. From your discussion with TyRaNiD, solving the problem of exporting the mangled named functions didn't seem to be worth the pain.

Nevermind, then :)

Raf.
white rabbit
Posts: 60
Joined: Wed Jul 06, 2005 7:03 pm

Post by white rabbit »

TyRaNiD wrote:Well for a start once you have the mangled names dont stick it in a cpp file , Else you are going to get potentially menagled names for mangled names ;)

Of course your real issue is you are trying no doubt to make a kernel module or at least disabled the use of newlib. I really wouldn't use c++ in a kernel module anyway :)
haha! I hadn't thought of psp-g++ mangling the mangled names!! D'Oh!

Well, I've re-done it with an export.c, but still no joy...

My code (I am testing to create a cpp class based, pure epxort prx) is...

main.cpp (or main.c)

Code: Select all

#include <pspkernel.h>

PSP_NO_CREATE_MAIN_THREAD&#40;&#41;;
PSP_MODULE_INFO&#40; "foo Test PRX", 0, 1, 1 &#41;;

/*
int main&#40; int argc, char **argv &#41;
&#123;
&#125;
*/
foo.h

Code: Select all

class Foo
&#123;
public&#58;
	Foo&#40;&#41;;
	~Foo&#40;&#41;;

	void Bar&#40;&#41;;
	int Bar&#40; int &#41;;
&#125;;
foo.cpp

Code: Select all

#include "foo.h"

Foo&#58;&#58;Foo&#40;&#41;
&#123;
&#125;

Foo&#58;&#58;~Foo&#40;&#41;
&#123;
&#125;

void Foo&#58;&#58;Bar&#40;&#41;
&#123;
&#125;

int Foo&#58;&#58;Bar&#40; int i &#41;
&#123;
	return i - 1;
&#125;
export.exp

Code: Select all

PSP_BEGIN_EXPORTS

PSP_EXPORT_START&#40; syslib, 0, 0x8000 &#41;
PSP_EXPORT_FUNC&#40; module_start &#41;
PSP_EXPORT_VAR&#40; module_info &#41;
PSP_EXPORT_END

PSP_EXPORT_START&#40; foo, 0, 0x0001 &#41;
PSP_EXPORT_FUNC&#40; _ZN3Foo3BarEi &#41;
PSP_EXPORT_FUNC&#40; _ZN3Foo3BarEv &#41;
PSP_EXPORT_FUNC&#40; _ZN3FooC1Ev &#41;
PSP_EXPORT_FUNC&#40; _ZN3FooC2Ev &#41;
PSP_EXPORT_FUNC&#40; _ZN3FooD1Ev &#41;
PSP_EXPORT_FUNC&#40; _ZN3FooD2Ev &#41;
PSP_EXPORT_END

PSP_END_EXPORTS
As you can see, I use the PSP_NO_CREATE_MAIN_THREAD() call, but I still need a main() function in my code. If I comment it out (as above) the link phase raises a crt0_prx.o undef ref to main in _main() error (along with the other two I mentioned before).

I am planning for the code which uses the prx to have access to foo.h and (obviously) foo.s at compile time.

The idea of using c factory functions to get a pointer to a new class interfaces is good. I'm a bit annoyed I haven't thought of it before as I use the pattern / idiom at work faily regularly.

I think the crt0_prx.o link errors won't go away, unless I use libpspc or similar, using -lstdc++ doesn't fix it :(

I'm using loser's precompiled sdk from last year, so I really should get SVN working and get the latest SDK and see if this all just goes away...
Anissian
Posts: 16
Joined: Fri Jan 26, 2007 8:40 pm

Post by Anissian »

white rabbit wrote: As you can see, I use the PSP_NO_CREATE_MAIN_THREAD() call, but I still need a main() function in my code. If I comment it out (as above) the link phase raises a crt0_prx.o undef ref to main in _main() error (along with the other two I mentioned before).
I am unsure whether you want kernel mode or user mode. You may want to play around with

Code: Select all

USE_KERNEL_LIBC=1
USE_KERNEL_LIBS=1
LDFLAGS = -mno-crt0 -nostartfiles
BUILD_PRX = 1
PRX_EXPORTS = modulo.exp
that said... 3.10 OE seems to make thinks easier, I have (for user mode) used PSPSDK_LIBS succesfully in C++
I am planning for the code which uses the prx to have access to foo.h and (obviously) foo.s at compile time.
There is an issue you may need to address (this is why I insist on *static* member functions in my posts), regardless of name mangling or not, and is the _implicit this pointer_ in class members. There are lots more issues with this C/c++ code interfacing such as alignment, typesafing, pointers to base objects, etc.(apologies if you are aware of this). You can safely access a C++ object's data from a C function if the C++ class (these are generic, and may not be a problem, also using gcc uniformly is a plus):

* Has no virtual functions (including inherited virtual functions)
* Has all its data in the same access-level section (private/protected/public)
* Has no fully-contained subobjects with virtual functions

check the c++ FAQ (c++-faq/mixing-c-and-cpp.html) or http://www.usenix.org/publications/libr ... oldstein.a
The idea of using c factory functions to get a pointer to a new class interfaces is good. I'm a bit annoyed I haven't thought of it before as I use the pattern / idiom at work faily regularly.
that's what I did. It seems clean and nice design.
I think the crt0_prx.o link errors won't go away, unless I use libpspc or similar, using -lstdc++ doesn't fix it :(
as suggested, I would try the -mno-crt flags, aliasing the main to module_start and NO_MAIN_THREAD. Personally, I have no problems with this, you may need an updated sdk, the PSPSDK LIBS seem to work fine with c++ (user mode apps, PRX within a PBP, 3.03 OE) and newlib.
I'm using loser's precompiled sdk from last year, so I really should get SVN working and get the latest SDK and see if this all just goes away...
definitely, yes.
Post Reply