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