Open ryandesign opened 1 year ago
I have not gone down the standalone code resource path yet because it seems like it would have many drawbacks so I consider it a last resort. And I'm not really looking at PPC yet because I understand 68K better.
To convert the MPW 68K libraries (which look like they're just object files), interfaces-and-libraries.sh uses Retro68's ConvertObj to convert an MPW object file into a rudimentary assembly representation, sends that to m68k-apple-macos-as to make a gcc-compatible object file, and then runs m68k-apple-macos-ar on it to make a gcc-compatible archive out of it. The assembly is rudimentary in that it represents everything just as bytes; it doesn't attempt to show the instructions that those bytes represent.
ConvertObj doesn't appear to be designed to read CodeWarrior object files. (I found one CW object decoder—mwobdec—but I don't know if it works, it was only designed for the Metrowerks PowerPC compiler on BeOS, and it is written in C# using Microsoft Visual Studio, neither of which I know anything about. This converter claims to be based on documentation of the CW object format; I've requested a copy of this documentation.)
CodeWarrior Pro 5 and earlier does come with the MPW tools MWDump68K/MWDumpPPC to convert CW objects and libraries to assembly. (In CW Pro 6, this functionality has moved to MWLink68K/MWLinkPPC with the -dis
flag.) I thought I might be able to get this output into a form that m68k-apple-macos-as would accept, but they appear to use rather different assembly syntaxes. Perhaps I can write a converter. (I found one assembly converter—mot2as—but it is insufficient.)
Distressingly, even a simple tiny function seems to involve the use of CW library functions. This simple C function:
int answer(void)
{
int a = 6;
int b = 7;
return a * b;
}
compiled with MWC68K with optimizations off and disassembled with MWDump68K becomes:
Hunk: Kind=HUNK_GLOBAL_CODE Name="answer"(1) Size=38
00000000: 4E56 0000 link a6,#0
00000004: 2F04 move.l d4,-(a7)
00000006: 2F03 move.l d3,-(a7)
00000008: 7606 moveq #6,d3
0000000A: 7807 moveq #7,d4
0000000C: 2003 move.l d3,d0
0000000E: 2204 move.l d4,d1
00000010: 4EAD 0000 jsr __lmul__
00000014: 261F move.l (a7)+,d3
00000016: 281F move.l (a7)+,d4
00000018: 4E5E unlk a6
0000001A: 4E75 rts
0000001C: 8661 6E73 7765 dc.b 0x86,'answer',0x00
7200
00000024: 0000
XRef: Kind=HUNK_XREF_CODE16BIT Name="__lmul__"(2) #Pairs=1
Offset=$00000012 Value=$00000000
In other words, multiplication is handled by a CW library function __lmul__
; who knows how I find and include that library function, and how many other CW library functions will end up being required by the actual third-party library I'm trying to compile.
Just another progress update...
MWDump68K/MWDumpPPC to convert CW objects and libraries to assembly
MWDump68K outputs only the first 0x30 bytes of data hunks:
Hunk: Kind=HUNK_GLOBAL_IDATA Name="Curl_easyopts"(315) Size=3780
00000000: 00 00 00 00 28 18 04 00 00 00 00 00 00 00 00 00 '....(...........'
00000010: 00 D4 00 00 00 00 00 00 00 00 00 00 27 76 04 00 '.‘..........'v..'
00000020: 00 00 00 00 00 00 00 00 00 AB 00 00 00 00 00 00 '.........´......'
...
00000EC0: 00 00 00 00 '....'
That's the literal output, including the ...
line. MWDumpPPC outputs only the first 0x400 bytes of data hunks. I can't find an option to make them output the full data so this puts a dent in using MWDump directly, and a separate conversion tool (or an enhancement of the existing ConvertObj) would be needed.
A tool to convert MW objects to MPW objects, or an MW compiler/linker flag to generate MPW objects in the first place, seems like a thing that should already exist but I haven't found it yet. MW tools can read MPW objects, but I haven't found a way to make them write them.
a CW library function
__lmul__
; who knows how I find and include that library function
When a library or object is linked into a program with MWLink68K,__lmul__
and other anonymous glue functions magically appear in the application's CODE resource. I've found these glue functions embedded within MWLink68K's CODE resource, so that's a bit tricky. When linking the application with the -map
option, the map file shows that __lmul__
and glue functions are coming from __RuntimeModule__
:
Segment "Main" size=$054A rsrcid=1 JTindex=$0000 #JTEnts=$0000
__Startup__ $000004 size=$00010A extern file="__RuntimeModule__"
__decomp_data__ $00010E size=$000104 local
__reloc_compr__ $000212 size=$000074 local
__relocate__ $000286 size=$00002C local
__unrelocate__ $0002B2 size=$000032 local
__A5WorldCheck__ $0002E4 size=$000036 local
__A5WorldSetup__ $000312 size=$000036 local
__PatchSegmentMap__ $00031A size=$000010 local
__LOADSEG__ $00032A size=$0000C6 extern
__UNLOADSEG__ $0003F0 size=$000098 local
__PreInit__ $000488 size=$000002 extern
exit $00048A size=$000008 extern
__TrapUnpatch__ $000492 size=$000024 extern
__destroy_global_chain $0004B6 size=$000024 extern
__lmul__ $0004DA size=$000032 extern
__InitCode__ $00050C size=$000002 extern
answer $00050E size=$000026 extern file="answer.c"
main $000534 size=$000016 extern file="main.c"
the standalone code resource path
I have begun looking into this, but as anticipated it is a bit of work. For one thing, every public API function will need a glue function that calls the code resource. There is some complication with the functions that have variadic arguments.
The code resource will end up containing the entire library, even functions the application doesn't use; no opportunity for dead code stripping. So that'll make the final application larger than it needs to be. I could manually keep track of which library functions I use in my app and only include those in the code resource.
And for a 68K code resource to work at all, it has to reference its global data via A4 not A5. I can of course compile the library with the flags to do that, but the library depends on GUSI which comes with pre-compiled libraries built for A5. It also comes with build scripts so I will have to see if I can get those working and then modified to build for A4.
I'm hopeful that the code resource path will not be necessary for PPC and that and I can find a way to convert a PPC MW library/object to an MPW library/object.
The library does not currently compile with Apple's MPW compilers SC and MrC, though getting that to work is another avenue I may pursue.
I'm developing an app with Retro68 and I would like to call a third-party library that cannot be compiled with Retro68 but which can be compiled with CodeWarrior.
Is there a way to convert the compiled 68K and PPC libraries that CodeWarrior creates into a form that I can link my app with when using Retro68? I had hoped I could use a method similar to what interfaces-and-libraries.sh does, but I suspect that was designed for MPW's object format, not CodeWarrior's.
If I cannot convert them, I think I will have to have CodeWarrior compile them into a standalone code resource which my Retro68 app can then load and call, but this will involve a bit of work in wrapping the interface.