#? お魚さんmemcpyの謎。(2006-02/20)
今、解らないのが「お魚さんmemcpyの謎」
「src/loadrom.c」というプログラム。(日本語で注記した点以外重要な点はない。これを詳しく読んでも意味はない。)
int funcUnzipCallback(int nCallbackId,省略,unsigned long ulUserData)
{
const char *pszFileName;
const unsigned char *pbData;
switch(nCallbackId) {
case UZCB_FIND_FILE:
pszFileName = (const char *)pData;
switch( ulUserData ){
case 0:
{
char path[MAXPATH];
memcpy( path, (unsigned char*)pszFileName, MAXPATH);←ここは「UNZIPLIB.A」のmemcpyを使う。
if( !smdchk(path) ){
return UZCBR_PASS;
}else
if( ulExtractSize < 0x400000 ){
char patch[MAXPATH];
fsize=0;
return UZCBR_OK;
}else{
return UZCBR_CANCEL;
}
}
break;
}
break;
case UZCB_EXTRACT_PROGRESS:
pbData = (const unsigned char *)pData;
switch( ulUserData ){
case 0:
{
char *p=(void *)ulCurrentPosition;
_memcpy( (void *)&cart_rom[fsize], (void *)pData, ulDataSize);←ここは「_CLIB.C」の_memcpyを使う。
fsize += ulDataSize;
}
break;
以下略
長いコメントは省略した。
どおして、同じ、スイッチ内で、違うmemcpyを呼んでるんだ?
中身はこう。
「UNZIPLIB.A」のmemcpy
void* ___memcpy(void *buf1, const void *buf2, int n) //←この'const'はあくまでこの関数内で、値が変わらないだろう事を保証してるに過ぎない。念のため。
{
while(n-->0)
((unsigned char*)buf1)[n] = ((unsigned char*)buf2)[n];
return buf1; // ←さしあたり使用してないので、あってもなくても「src/loadrom.c」にとっては、同じ
}
「_CLIB.C」のmemcpy
void _memcpy(void *d, void *s, unsigned long n)
{
/* このコメント内は書式が違うだけで、(考え方は)上とほぼ同じもの。(但しコードは変わるはず)
GCC400なら、「(*(((unsigned char *)d++))=*(((unsigned char *)s++)));」と書かないと、コンパイルが、
通らない。( -std=gnu99 とかいうオプションの「数字(年度)」を古くすれば通るのかも知れない。)
for (; n>0; n--) {
(*(((unsigned char *)d)++)=*(((unsigned char *)s)++));
}
*/
if( (unsigned int)d & 3 || (unsigned int)s & 3 || n & 3 ){
char *g=s;
char *p=d;
while(n--)*p++=*g++;
}else{
unsigned int *g=s;
unsigned int *p=d;
n>>=2;
while(n--)*p++=*g++;
}
}
「UNZIPLIB.A」のmemcpyは、void型のポインタを返しているが、お魚さんでそれを利用している場所は、
一ヶ所もないので、お魚さんにとっては、あってもなくても同じ。(UNZIPLIB.A内では違うかもしれん)
「_CLIB.C」のmemcpyはalignを考えて転送してるが、もしこの問題がないのならば(ないと踏んでいる)
基本的に(「UNZIPLIB.A」のmemcpyと「_CLIB.C」の_memcpyは)動作はまったく一緒。
で、「src/loadrom.c」で、上に揚げた部分の「_memcpy」を「memcpy」に変えて、コンパイルしてみると、
なんとコンパイルが通らない。
なんで??
(管理人、C++なら納得するよ、引数違うもん。でもこれは純粋なC言語だよ。ワーニングが出てて、
仮にキャストされないとしても(されるに決まってるが)リンク出来ないのは明らかにおかしい。)
標準の場合
$ make
psp-gcc-4.0.0 -O3 -mgp32 -mlong32 -msingle-float -mabi=eabi -c src/loadrom.c -o
obj/loadrom.o
src/loadrom.c: In function 'funcUnzipCallback':
src/loadrom.c:59: warning: incompatible implicit declaration of built-in functio
n 'memcpy'
ld -O0 obj/startup.o obj/error.o obj/io.o obj/cpu/m68kcpu.o obj/cpu/m68kops.o ob
j/cpu/m68kopac.o obj/cpu/m68kopdm.o obj/cpu/m68kopnz.o obj/cpu/z80.o obj/sound/f
m.o obj/sound/sn76496.o obj/sound/sound.o obj/render.o obj/system.o obj/vdp.o ob
j/loadrom.o obj/genesis.o obj/mem68k.o obj/membnk.o obj/memvdp.o obj/memz80.o ob
j/_clib.o obj/pg.o obj/main.o obj/main_sub.o obj/main_text.o obj/main_sound.o ob
j/menu.o unziplib.a -M -Ttext 8900000 -q -o mdpsp.out > main.map
./outpatch.exe mdpsp.out mdpsp.outp "USERPROG"
successed filesize:00158497 modulename:000CCEA4 scemoduleinfo:000F7967
./elf2pbp.exe mdpsp.outp "MEGADRIVE0.22A04A(for JIKKEN)" ICON0.PNG
Elf2Pbp v0.3 - loser 2005 +PNG
successfully generated pbp file
ワーニングが出るものの。コンパイル成功EBOOT.PBP作成。OK.
「src/loadrom.c」で、上に揚げた部分の「_memcpy」を「memcpy」に変えた場合。
$ make
psp-gcc-4.0.0 -O3 -mgp32 -mlong32 -msingle-float -mabi=eabi -c src/loadrom.c -o
obj/loadrom.o
src/loadrom.c: In function 'funcUnzipCallback':
src/loadrom.c:59: warning: incompatible implicit declaration of built-in functio
n 'memcpy'
src/loadrom.c:93: warning: incompatible implicit declaration of built-in functio
n 'memcpy'
ld -O0 obj/startup.o obj/error.o obj/io.o obj/cpu/m68kcpu.o obj/cpu/m68kops.o ob
j/cpu/m68kopac.o obj/cpu/m68kopdm.o obj/cpu/m68kopnz.o obj/cpu/z80.o obj/sound/f
m.o obj/sound/sn76496.o obj/sound/sound.o obj/render.o obj/system.o obj/vdp.o ob
j/loadrom.o obj/genesis.o obj/mem68k.o obj/membnk.o obj/memvdp.o obj/memz80.o ob
j/_clib.o obj/pg.o obj/main.o obj/main_sub.o obj/main_text.o obj/main_sound.o ob
j/menu.o unziplib.a -M -Ttext 8900000 -q -o mdpsp.out > main.map
obj/loadrom.o: In function `funcUnzipCallback':
loadrom.c:(.text+0x5ec): undefined reference to `memcpy'
make: *** [mdpsp.out] Error 1
一つ目のワーニングはさっきと同じもの。
ワーニングが出て。コンパイルは出来るが、リンカでこける(SYS1と同じ状態)
EBOOT.PBP作成出来ない。
これが噂の「遠い近い問題」なんだろうか。この件が解決しない限り、SYS1は出来ないし、
ソースのそこらじゅうに、似たようなルーチンをちりばめなくてはならなくなる。
しかし、何で同じスイッチ内で、こんな事がおきるのだ?詳しく調査する必要がある。
要は現状のSYS1がEBOOT.PBPにならない問題を解りやすく纏めてみた。不思議でしょ?
(2006-02/20、19:33)
現状別館にあがってる、「MD022A04A」で全く同じ実験が出来る。
(だってSYS1ばっかやって、そっちは進んでないもん)
ちなみに、MAPファイルを出力させ、比較してみたが、全く同じものを吐いた。
memcpyと_memcpyのエントリーは、(MAPファイルだよ)
.text 0x000000000898b9c8 0x2ec obj/_clib.o
0x000000000898b9f0 _strcat
0x000000000898ba2c _strncpy
0x000000000898bbd4 _memcpy ←これが_CLIB.C版
0x000000000898bad4 _memset
0x000000000898ba64 _strchr
0x000000000898b9c8 _strcpy
0x000000000898bb5c _memcmp
0x000000000898bc48 _strrchr
0x000000000898baa8 _strlen
.text 0x0000000008991550 0x4d4 unziplib.a(zlibFileMemory.o)
0x000000000899167c ___ftell
0x0000000008991718 _(float, long double,...)(...)
0x00000000089917c8 ___strcat
0x0000000008991638 ___fopen
0x000000000899184c ___itoa
0x00000000089916e0 ___fread
0x0000000008991684 ___fseek
0x00000000089916d8 ___ferror
0x0000000008991550 ___memcpy ←これがUNZIPLIB.A版
0x0000000008991674 ___fwrite
0x0000000008991584 ___strcmp
0x00000000089915c8 ___strlen
0x00000000089916b4 ___fclose
0x0000000008991720 ___calloc
0x00000000089915f4 ___strcpy
0x000000000899175c ___strrev
0x0000000008991948 ___itoa32
0x0000000008991728 ___malloc
■
■