#10 やっと迷走の謎が解けた。と思ったら、新たな謎が。(2006-02/19) | //www.旧型、PSP開発幼稚園.game.jp/(本館)

#10 やっと迷走の謎が解けた。と思ったら、新たな謎が。(2006-02/19)

#10 やっと迷走の謎が解けた。と思ったら、新たな謎が。(2006-02/19)

今回は、随分長い、迷走だった。MAMEつーくろ!って思ったのが、(02/13)。
今日は(02/19)だから、5日間も迷走してたな。

初心者は3日迷走で、何とかなる。と思ったが、今回は5日だもんな。

大変だよ。まったく。


今回の謎の鍵は、RUKAさんの「UNZIPLIB.A」にあった。 昨日調べたんじゃなかったのかって? いや、見逃した。 全ての答えは、「zlibFileMemory.c」にある。
「zlibFileMemory.c」全文掲載。
#include "zlibFileMemory.h" #include "zlibType.h" #include "zconf.h" #include "syscall.h" void ___itoa(int val, char *s) { char *t; int mod; if(val < 0) { *s++ = '-'; val = -val; } t = s; while(val) { mod = val % 10; *t++ = (char)mod + '0'; val /= 10; } if(s == t) *t++ = '0'; *t = '\0'; ___strrev(s); } void ___itoa32(unsigned long val, char *s) { char *t; unsigned long mod; if(val < 0) { *s++ = '-'; val = -val; } t = s; while(val) { mod = val % 10; *t++ = (char)mod + '0'; val /= 10; } if(s == t) *t++ = '0'; *t = '\0'; ___strrev(s); } void* ___memcpy(void *buf1, const void *buf2, int n) { while(n-->0) ((unsigned char*)buf1)[n] = ((unsigned char*)buf2)[n]; return buf1; } int ___strcmp(const char *str1, const char *str2) { char c1, c2; for(;;){ c1 = *str1; c2 = *str2; if(c1!=c2) return 1; else if(c1==0) return 0; str1++; str2++; } } size_t ___strlen(const char *s) { int ret; for(ret=0; s[ret]; ret++) ; return ret; } char* ___strcpy(char *dest, const char *src) { int i; for(i=0; src[i]; i++) dest[i] = src[i]; dest[i] = 0; return dest; } void ___strrev(char *s){ char tmp; int i; int len = ___strlen(s); for(i=0; i < len/2; i++){ tmp = s[i]; s[i] = s[len-1-i]; s[len-1-i] = tmp; } } char* ___strcat(char *dest, const char *src) { int i; int len; len=___strlen(dest); for(i=0; src[i]; i++) dest[len+i] = src[i]; dest[len+i] = 0; return dest; } //FILE ___zlibfb; #define MAX_PATH 260 #define AllocBuffSize 65536 //unsigned long long ___zlibTmpBuffSize; //unsigned char *___zlibTmpBuff; //作業用。入力zipをここに展開する //unsigned int ___zlibInZipBuffPointer; //上記メモリをどこまで使ったか //unsigned char ___zlibInZipFileName[MAX_PATH]; //作業用。入力zipをここに展開する //unsigned int ___zlibInZipSize; //入力zipの大きさ[バイト] typedef struct { int nFileId; // file id unsigned long ulPtr; // file pointer }zlibInFile; unsigned char ___zlibAllocBuff[AllocBuffSize]; //メモリの確保 unsigned int ___zlibAllocBuffPointer; //上記メモリをどこまで使ったか zlibInFile ___zlibInFile = {0, 0}; FILE *___fopen( const char *filename, const char *mode ) { int fb1; fb1 = sceIoOpen(filename,O_RDONLY,0777); if(fb1 < 0) { return NULL; } ___zlibInFile.nFileId = fb1; ___zlibInFile.ulPtr = 0; ___zlibAllocBuffPointer = 0; return (FILE *)&___zlibInFile; } size_t ___fwrite( const void*buffer, size_t size, size_t count, FILE *stream ) { return 0; } long ___ftell( FILE *stream ) { return ___zlibInFile.ulPtr; } int ___fseek( FILE *stream, long offset, int origin ) { unsigned long ulPtr; ulPtr = sceIoLseek(___zlibInFile.nFileId, offset, origin); ___zlibInFile.ulPtr = ulPtr; return ulPtr; } int ___fclose( FILE *stream ) { sceIoClose(___zlibInFile.nFileId); return 0; } int ___ferror( FILE *stream ) { return 0; } size_t ___fread( void *buffer, size_t size, size_t count, FILE *stream ) { int ret = 0; int readSize = size * count; readSize = sceIoRead(___zlibInFile.nFileId, buffer, readSize); ___zlibInFile.ulPtr += readSize; return readSize; } void ___free( void *memblock ) { return; } void *___calloc( size_t num, size_t size ) { return NULL; } void *___malloc( size_t size ) { ___zlibAllocBuffPointer += size; if(___zlibAllocBuffPointer > AllocBuffSize) { // メモリ不足 return NULL; } return &___zlibAllocBuff[___zlibAllocBuffPointer - size]; }
こいつらが、「お魚さん」が暗黙にリンクしていた。標準ライブラリの正体だ。 中身は、何て事ない。 「UNZIPLIB.A」は標準LIBとバッティングする標準的な機能をこれだけ持っている。 管理人が「UNZIPLIB.A」のコンパイルすら出来ない時代に、バイナリでシンボルを チェックした時も、こいつらはあったよな。 ここで、注目して欲しいのは、中身の話ではない。 これの使い方だ。
■たとえば、この「_ _ _strcmp()」を呼ぶのは、「_ _ _strcmp()」と書いて、CALLするのではない。 単に「strcmp()」と書けば、良い。アンダースコアが、前に3つついてるファイルは、 (GCCの場合)リンカが標準LIBとして、リンクしてくれる仕組みの様だ。 もし、自作のLIBもどき「_strcmp()」が同時にあった場合はどおなるか。これは、どおもならない。 だから、呼ぶ時は当然「_strcmp()」で呼べば良い。 お魚さんのプログラムは「UNZIPLIB.A」をリンクしてるにもかかわらず、 自作のLIB「_clib.c」をリンクしている。これの中身は、
void _strcpy(char *d,const char *s) { for (; *s!=0; ++s, ++d) *d=*s; *d=0; }
極一部だが、こんな感じ。 「strcpy()」と「_strcpy()」を意味もなく、両方使っている。
管理人はプログラムをチェックしたから、知っているが、両方なければ、現状は動かない筈だ。 現状正常に動いている。だから、非常に謎だった。 プログラムの仕組みからすれば、どちらか片方使えば良い。 つまり、お魚さんも、気が付かなかった。あるいは忙しいから気が付いていたけど放置した。もしくは、 そんな事は本質(ゲームで遊ぶ事)に対して、さして重要ではないから、拘らなかった。 と言う事だろう。
とにかく、これでライブラリの謎が全て解けた。 纏めると
■ 1.GCC400標準の(PSP用)LIBC.Aは、2.7MBあり、(PSP用)GCC400では、リンカの機能が低く、 '-lc'をつけてリンクしても、現実のプログラム(例えばMAME)をEBOOT.PBPまで持っていくのは、 困難である。 これは、はっきり言って「出来ない」と解釈して差し支えない。小さいプログラムなら、リンクして動くかも知れ ないが、そんなものは管理人の興味の外である。
2.お魚さんは、結局標準ライブラリは、リンクしていなかった。管理人が「LIBC」?と誤解したのは、 実は、RUKA版「UNZIPLIB.A」内の関数だった。
これはMAPファイルに書いてあった。PSPのプログラミングでは、STARTUP.Sが避けてはとうれない様に、 MAPファイルを見る事も避けてはとうれない。これは内容の極一部を見ればいいだけなので、簡単である。 詳細を理解する必要等。何処にもない。 MAPファイルから、収集しなければいけない情報は、 「具体的に何処のパスのどんなOBJをリンクしているのか。」だけである。 アドレス配置などの余分な情報は、特に見る必要も、理解する必要もない。 (もちっと、中級者になれば、それはそれで、重要かも知れないが) 要するに、このファイルを見る目的は「本当にやったかどうか確認する」そんだけ。
■じゃあMAMEはどおすんの? LIBC.Aはリンクできない。から自前でLIBCを作るしか道はあるまい。 これ以外の答えは恐らくない。 後は新しい開発環境を漁るか、古い開発環境を漁るか。 とにかくこの環境ではリンカのVERが変わらない限り、多分無理。(2006-02/19-23:28)
■と、思ったんだけど、ちょっとまって! Makefileから、LIBCを外して、 $(LD) -O0 $^ $(LIBS) ./libc.a ./libcfe.a -lc -M -Ttext 8900000 -q -o out > main.map → $(LD) -O0 $^ $(LIBS) -lc -M -Ttext 8900000 -q -o out > main.map makeしてみたけど、結果は同じ。まあLIBCがあるとできない説もあるけど、 やっぱり出来るのかもしんない。(おい、どっちかはっきりしろ) それ以前に、違う要因でこけてる。
../../../../../newlib/libc/stdlib/dtoa.c:511: undefined reference to `__muldf3' ../../../../../newlib/libc/stdlib/dtoa.c:513: undefined reference to `__fixdfsi' ../../../../../newlib/libc/stdlib/dtoa.c:514: undefined reference to `__floatsidf' ../../../../../newlib/libc/stdlib/dtoa.c:514: undefined reference to `__subdf3' ../../../../../newlib/libc/stdlib/dtoa.c:518: undefined reference to `__adddf3' ../../../../../newlib/libc/stdlib/dtoa.c:518: undefined reference to `__ltdf2' ../../../../../newlib/libc/stdlib/dtoa.c:520: undefined reference to `__subdf3' ../../../../../newlib/libc/stdlib/dtoa.c:520: undefined reference to `__gtdf2' ../../../../../newlib/libc/stdlib/dtoa.c:343: undefined reference to `__adddf3' ../../../../../newlib/libc/stdlib/dtoa.c:442: undefined reference to `__divdf3' /usr/local/pspdev/psp/bin/../psp/lib/libc.a(mprec.o): In function `_ratio': ../../../../../newlib/libc/stdlib/mprec.c:943: undefined reference to `__divdf3' ../../../../../newlib/libc/stdlib/mprec.c:943: undefined reference to `__divdf3' /usr/local/pspdev/psp/bin/../psp/lib/libc.a(mprec.o): In function `_mprec_log10': ../../../../../newlib/libc/stdlib/mprec.c:983: undefined reference to `__muldf3' make: *** [EBOOT.PBP] Error 1 こいつらは、一体何?もし、こいつらがLIBC内の関数で、LIBCがでかいから届かない。 んなら辻褄はあう。でも、もしこいつらがLIBC外の関数だった場合は、話が全く違う。
cpuexec.c:(.text+0x1ec8): undefined reference to `__extendsfdf2' cpuexec.c:(.text+0x1edc): undefined reference to `__gedf2' cpuexec.c:(.text+0x1ef4): undefined reference to `__fixsfdi' cpuexec.c:(.text+0x1f10): undefined reference to `__fixsfdi' obj/namcos1psp2/cpuexec.o: In function `cpu_boost_interleave': cpuexec.c:(.text+0x1fc0): undefined reference to `__extendsfdf2' cpuexec.c:(.text+0x1fdc): undefined reference to `__gedf2' cpuexec.c:(.text+0x2014): undefined reference to `__extendsfdf2' cpuexec.c:(.text+0x2028): undefined reference to `__gedf2' cpuexec.c:(.text+0x2138): undefined reference to `__fixsfdi' cpuexec.c:(.text+0x2154): undefined reference to `__fixsfdi' cpuexec.c:(.text+0x216c): undefined reference to `__fixsfdi' cpuexec.c:(.text+0x2188): undefined reference to `__fixsfdi' obj/namcos1psp2/cpuexec.o: In function `cpu_compute_scanline_timing': cpuexec.c:(.text+0x2224): undefined reference to `__extendsfdf2' cpuexec.c:(.text+0x2240): undefined reference to `__gedf2' cpuexec.c:(.text+0x22b4): undefined reference to `__extendsfdf2' cpuexec.c:(.text+0x22c8): undefined reference to `__gedf2' 例えばこの辺は、「みえねー」って言ってるだけで、具体的に「どこ」が見えないのか、 全然判らん。「どこ」が「LIBC」なら、問題は解決なんだが「違うとこ」が見えなかった場合は、 全く別問題だ。具体的な情報は無い。
そもそもMAMEのmakeのこの辺のオプションはそおいう意味で怪しくないか? ifdef SYMBOLS CFLAGS += -O0 -Wall -Wno-unused -g else CFLAGS += -DNDEBUG \ $(ARCH) -O3 -fomit-frame-pointer -fno-strict-aliasing \ -Wall -Wno-sign-compare -Wunused \ -Wpointer-arith -Wbad-function-cast -Wcast-align \ -Wstrict-prototypes -Wundef \ -Wformat-security -Wwrite-strings \ -Wdisabled-optimization \ #TMK -Werror -Wall -Wno-sign-compare -Wunused -Wno-unused-functions \ # -Wredundant-decls # -Wfloat-equal # -Wunreachable-code -Wpadded # -W had to remove because of the "missing initializer" warning # -Wlarger-than-262144 \ # -Wcast-qual \ # -Wconversion \ # -Wmissing-prototypes \ # -Wmissing-declarations endif この辺のオプションを一つ一つ精査する必要があるかもしれん。(そしたらうまくいく可能性がある。) (2006-02/19、23:59)