Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using old Think C-compatible library crashes system when linked by retro68's toolchain #254

Closed
briankendall opened this issue Jun 25, 2024 · 7 comments

Comments

@briankendall
Copy link
Contributor

Kind of in a similar vein to #197, I have an old Mac library that I'd like to use in my retro68 project that's in the library format of Think C / Symantec C++. Looking inside the library, it all appears to be in the resource fork, and it contains a CODE resource, a NAME resource that contains the names of its functions, and a SYMS and a JUMP resource that I'm not sure precisely what their purpose is. (There are several other resources that all contain no data.)

Is there any known way of converting it into a format that can be linked by retro68 / gcc?

@briankendall
Copy link
Contributor Author

Update: I was successful in turning the library into a gcc static library! It basically involved manually figuring out where the symbols in the file were -- I still haven't figured out exactly how to use the SYMS, JUMP, and NAME resources in a Think C library to determine where the named symbols are --and then converting it into a .s file, with lots of use of .byte. Once I compiled it and packaged it into a static library, I was able to link to it and call its functions!

However, it doesn't quite work. Some of the functions work as expected. There's one in particular that simply copies a string into a passed in Str255 that works properly. But the other ones end up crashing the system. I'm not sure why.

The library I'm working with specifically is the Sound-Trecker driver. It's a bit of an odd case, in that the way it works is that its functions are stored in PSTk and ISTk resources which basically just contain compiled code. The Symantec library I was working with just contains stub functions that load the resources and then jump execution to the correct place in the resource.

No matter how I call into these functions, though, I end up getting a system error (if not an outright snow crash) when it's compiled with retro68 rather than Symantec C++. Everything that works in Symantec doesn't seem to work in retro68.

The last thing I just tried was determining where the actual non-stub function calls are in the PSTk / ISTk resources, and then converting the whole resources into static libraries, so no more need for loading resources and dubiously sending execution into their data. However it still crashes in precisely the same way. Same results if I explicitly turn of compiler optimizations, too.

I'm not very skilled with 68k assembler (though this project has gotten me a lot more fluent in it!) so at this stage I have no idea why it these libraries don't work as expected. The fact that one of the functions does work lends me to believe that I'm on the right track, but that there's some subtlety of how everything is being linked together that is breaking it.

If anyone can help out, I'd be most appreciative! Maybe there's some arcane compiler options I need to use to get this working...?

@briankendall briankendall changed the title Is it possible to use Think C / Symantec C++ libraries? Using old Think C library crashes system when linked by retro68's toolchain Jun 28, 2024
@briankendall briankendall changed the title Using old Think C library crashes system when linked by retro68's toolchain Using old Think C-compatible library crashes system when linked by retro68's toolchain Jun 28, 2024
@briankendall
Copy link
Contributor Author

I've gone ahead and renamed the issue, since what it originally started out as -- trying to use a Think C library with Retro68 -- has turned into something fairly different. While I did figure out how to (manually) convert a Think C library to a gcc-compatible static library, and at least a few of the functions in the library works, the issue now is that using most of the other functions causes a system crash when called by a retro68-compiled application.

I've got a few more clues as to what could be going on... I tried using this library in a CodeWarrior project, compiled in an (emulated) Mac OS 8.1 system. Rather than creating a new CodeWarrior compatible stub library, what I went ahead and did was create an app that loads the resources containing the code and then uses function pointers that call directly into the functions:

pascal OSErr (*OpenPChannel)(int channels, Byte flags, int playFrames, PChannelPtr* pc) = NULL;
pascal void (*PChannelVolume)(PChannelPtr pc, int chan, Fixed volume) = NULL;
pascal void (*ClosePChannel)(PChannelPtr pc) = NULL;
pascal void (*StopPChannel)(PChannelPtr pc, Boolean fadeOut) = NULL;
pascal void (*ResetPChannel)(PChannelPtr pc) = NULL;
pascal OSErr (*StartPChannel)(PChannelPtr pc) = NULL;
pascal void (*UnlinkSoundTrack)(SoundTrackHandle sth) = NULL;
pascal void (*DisposeSoundTrack)(SoundTrackHandle sth) = NULL;
pascal OSErr (*GetSoundTrack)(int vRefNum, StringPtr fName, Byte ldOverSampling, SoundTrackHandle* sth, Boolean check) = NULL;
pascal WorkspacePtr (*GetSoundTrackWorkspace)(SoundTrackHandle sth) = NULL;
pascal void (*LinkSoundTrack)(SoundTrackHandle sth, PChannelPtr pc) = NULL;

PSTkHandle = GetResource('PSTk', 128);
if (PSTkHandle == NULL) {
    // program exits here
    return 1;
}
HNoPurge(PSTkHandle);
HLock(PSTkHandle);

ISTkHandle = GetResource('ISTk', 128);
if (ISTkHandle == NULL) {
    // program exits here
    return 1;
}
HNoPurge(ISTkHandle);
HLock(ISTkHandle);

OpenPChannel = (void *)((*PSTkHandle) + 0xff0);
PChannelVolume = (void *)((*PSTkHandle) + 0x1af8);
ClosePChannel = (void *)((*PSTkHandle) + 0xb82);
StopPChannel = (void *)((*PSTkHandle) + 0xb36);
ResetPChannel = (void *)((*PSTkHandle) + 0xc80);
StartPChannel = (void *)((*PSTkHandle) + 0xca2);
UnlinkSoundTrack = (void *)((*ISTkHandle) + 0x5a5c);
DisposeSoundTrack = (void *)((*ISTkHandle) + 0xe1c);
GetSoundTrack = (void *)((*ISTkHandle) + 0x44c2);
GetSoundTrackWorkspace = (void *)((*ISTkHandle) + 0x5c0a);
LinkSoundTrack = (void *)((*ISTkHandle) + 0x5b1a);

This method works great in Think C / Symantec C++.

What's interesting, though, is that it works in some versions of CodeWarrior but not all. The two versions I tried were CodeWarrior Gold 9, in which it does work, and CodeWarrior Gold 11, in which it doesn't.

In the latter case, if I run the app it produces in System 7.5, I get a nasty system crash. (One that actually corrupted the system volume!) If I run it in System 8.1, it doesn't get as far as crashing the system, and instead one of the functions fails with error code -43 "File not found":

Point openPoint = { 85, 100 };
SFTypeList theTypeList = { 'STrk' };
SFReply theReply;
SFGetFile (openPoint, "\p", NULL, 1, theTypeList, NULL, &theReply);
err = GetSoundTrack (theReply.vRefNum, theReply.fName, 0, &strk, FALSE); // error -43

So for some reason, it can't find the file given its volume reference number and file name, even though the same code works when compiled with Think C or CodeWarrior 9. I figure this is a clue, but I'm not sure what it means.

For what it's worth, compiling the same code with retro68 and running it in System 8.1 still causes a full system crash. So the bad results from compiling with retro68 don't mirror CodeWarrior 11.

@autc04
Copy link
Owner

autc04 commented Jun 28, 2024

Hmmm, sounds like an interesting puzzle.

So, first, let me ask, the THINK C library you mentioned was the stub library used to call the SoundTrecker code resources? Do you have source code for that or did you have to reverse-engineer it?

Were you able to verify in MacsBug that the function calls take you to the right place in the code resources?

@briankendall
Copy link
Contributor Author

So, first, let me ask, the THINK C library you mentioned was the stub library used to call the SoundTrecker code resources? Do you have source code for that or did you have to reverse-engineer it?

I had to reverse engineer it. Luckily, being stub functions, there's hardly anything to it. That said, I haven't figured out how to re-create those functions in a way that's compatible with gcc, since they use Think C-style inline assembler.

Were you able to verify in MacsBug that the function calls take you to the right place in the code resources?

I haven't used MacsBug, no, but given that it all works properly when compiled with Think C, I know I at least got the addresses of the functions inside those code resources correct. Is there any reason that, when compiled with gcc / retro68 (or CodeWarrior for that matter), calling a function pointing inside a code resource (i.e. like this: OpenPChannel = (void *)((*PSTkHandle) + 0xff0);) would have different behavior?

@briankendall
Copy link
Contributor Author

I figured it out! It was because of integer sizes. In Think C, an int is two bytes. With retro68, it's four bytes. Hence the function signatures were wrong, causing everything to blow up horribly. That also explains why some of the functions worked, but others didn't: any of them that had an int in its signature would crash and burn. This is the same reason CodeWarrior 11 crashed: its default int size is also four bytes, though you can change it to two bytes in the project settings. I discovered that as soon as I did that, everything started working.

I wondered why this didn't come up with the MPW libraries and headers, and then realized that Apple's headers -- quite wisely -- do not use ints anywhere, obviously because their size is unreliable. I knew that's the case, and yet it didn't occur to me to avoid them for this. But now I have learned that lesson like so many other before me.

@briankendall
Copy link
Contributor Author

Also, a quick addendum: once I got my ints sorted out, all of the different methods of calling these functions work: the static libraries I generated from the stubbed functions, loading the resources and calling into them, and converting the resources themselves into static libraries.

@jduerstock
Copy link

Nothing technical to add, but I am pleased to see your perseverance and eventual success. Keep up the good work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants