startup getmainargs
startup getmainargs
So win32 executables using msvcrt.dll need to do this (or similar):
https://sourceforge.net/p/pdos/gitcode/ ... w32start.c
__getmainargs(&argc, &argv, &environ, 0, &startinfo);
status = main(argc, argv);
exit(status);
I didn't really like that, so for PDOS-generic I created this:
https://sourceforge.net/p/pdos/gitcode/ ... pgastart.c
*__os->main = main;
return (__os->__start(0));
With MVS work that I am about to start, I realized I have a problem.
I can't tell whether an executable is PDOS-generic (ie the C runtime library isn't in the executable), or whether it is native MVS (the MVS-specific C runtime library is in the executable, and the PDOS-generic parameter is more-or-less just used to retrieve the SVC callback so that when it is time to do an MVS call via SVC (equivalent of INT xx on the 80x86), it does a callback to PDOS-generic instead of a real SVC).
My plan is to call the MVS executable with a parameter of 0xffffffff instead of the normal parameter containing the command line argument. And a "properly written" (TM) MVS application is expected to detect that and make use of the PDOS-generic second parm. Another option would be to make the first parameter on an odd address, and the startup code is meant to detect that and subtract 1 to get the PDOS-generic parameter, and then add 4 to get the normal parameter.
However, either way, I need to have done the start() processing myself before calling the executable, so that my runnum can be increased so that I know what files have been opened by this program, so that I can automatically close them.
And then when the application starts, it will be doing its own MVS-specific start() call to open SYSPRINT etc.
One day PDOS-generic may put in real SVC handlers to allow at least some non-PDOS-generic-aware programs to run, in which case I would stop fudging the parameters as an option in the OS itself.
Anyway, I am now considering making the MVS startup code to look the same as Win32. Allowing for theoretical DLLs on MVS too.
And it occurs to me that this (ie Win32 startup code) should in fact be some fundamental part of computer science (I think Windows NT was created by a DEC designer or something - maybe some computer science concept was carried across). I'm not aware of the concept myself, but I'm presumably stumbling into it now. Just thought I'd ask if it is a well-known concept that Win32 programs abide by, and it wasn't known at MSDOS time or whatever. Specifically you do a call to get the arguments and then you execute main. The startup code - if any - would need to exist in getmainargs.
https://sourceforge.net/p/pdos/gitcode/ ... w32start.c
__getmainargs(&argc, &argv, &environ, 0, &startinfo);
status = main(argc, argv);
exit(status);
I didn't really like that, so for PDOS-generic I created this:
https://sourceforge.net/p/pdos/gitcode/ ... pgastart.c
*__os->main = main;
return (__os->__start(0));
With MVS work that I am about to start, I realized I have a problem.
I can't tell whether an executable is PDOS-generic (ie the C runtime library isn't in the executable), or whether it is native MVS (the MVS-specific C runtime library is in the executable, and the PDOS-generic parameter is more-or-less just used to retrieve the SVC callback so that when it is time to do an MVS call via SVC (equivalent of INT xx on the 80x86), it does a callback to PDOS-generic instead of a real SVC).
My plan is to call the MVS executable with a parameter of 0xffffffff instead of the normal parameter containing the command line argument. And a "properly written" (TM) MVS application is expected to detect that and make use of the PDOS-generic second parm. Another option would be to make the first parameter on an odd address, and the startup code is meant to detect that and subtract 1 to get the PDOS-generic parameter, and then add 4 to get the normal parameter.
However, either way, I need to have done the start() processing myself before calling the executable, so that my runnum can be increased so that I know what files have been opened by this program, so that I can automatically close them.
And then when the application starts, it will be doing its own MVS-specific start() call to open SYSPRINT etc.
One day PDOS-generic may put in real SVC handlers to allow at least some non-PDOS-generic-aware programs to run, in which case I would stop fudging the parameters as an option in the OS itself.
Anyway, I am now considering making the MVS startup code to look the same as Win32. Allowing for theoretical DLLs on MVS too.
And it occurs to me that this (ie Win32 startup code) should in fact be some fundamental part of computer science (I think Windows NT was created by a DEC designer or something - maybe some computer science concept was carried across). I'm not aware of the concept myself, but I'm presumably stumbling into it now. Just thought I'd ask if it is a well-known concept that Win32 programs abide by, and it wasn't known at MSDOS time or whatever. Specifically you do a call to get the arguments and then you execute main. The startup code - if any - would need to exist in getmainargs.
-
- Member
- Posts: 5837
- Joined: Mon Mar 25, 2013 7:01 pm
Re: startup getmainargs
I don't think so. If anything, Microsoft probably would have preferred to have C programs export a main() symbol that would be called by msvcrt.dll so no one would be able to see internal functions like getmainargs().
"You" don't do those things, your C standard library does. The only reason you're doing those things for your programs is because you're implementing (part of) the C standard library.
The startup code is whatever runs before calling main(). Most of the startup code could be hidden in a function like getmainargs(), but the code calling getmainargs() is still part of the startup code.
Re: startup getmainargs
That's a good point - I didn't even think of that as a solution. Forest for the trees again. Regardless, main() is actually "exported" (externally visible) already, and could indeed be the entry point.Octocontrabass wrote: ↑Fri Jun 13, 2025 1:03 pmI don't think so. If anything, Microsoft probably would have preferred to have C programs export a main() symbol that would be called by msvcrt.dll so no one would be able to see internal functions like getmainargs().
However, having main() as an entry point means there is no chance for some setup code in the executable to be run. You could argue that in the case of a DLL (not necessarily exactly msvcrt.dll), none is needed. Because the linker has done some magic that allows the loader to insert DLL references, and that can solve the problem.
However, in my case, I don't want to rely on a special linker that can handle DLLs and add that burden to the loader either. I want something that is universal C90. ie C can take a parameter, in my case a pointer to a structure, and then it can internally store that for future use by the C library. So I can't get the OS (or OS component) to directly call main(). I need some startup code to put the parameter into a global variable. I could have argc and argv passed as additional parameters, and pass them on to main() without needing to call a getmainargs or similar.
PDPCLIB is a complete C90 standard library. But yes, that's an unusual thing that I failed to state. I have control of both the C library and the OS, and would like them to be "designed according to proper computer science" - if such a thing exists.
Sure.The startup code is whatever runs before calling main(). Most of the startup code could be hidden in a function like getmainargs(), but the code calling getmainargs() is still part of the startup code.
-
- Member
- Posts: 5837
- Joined: Mon Mar 25, 2013 7:01 pm
Re: startup getmainargs
A standard C program has no setup code, so the C standard library doesn't need to give you that chance.
I was thinking more along the lines of having the entry point be inside (the equivalent of) msvcrt.dll. This is actually how dynamic linking works in Linux: dynamically linked ELF executables specify that ld-linux.so contains the entry point. (I'm not sure how you'd make this work for both dynamic linking and the C standard library at the same time.)
I'm not sure I understand what you mean by "universal". Startup code is OS-specific.
As far as I know, no such thing exists. There are tradeoffs and compromises, and what works best for one OS might not be the right fit for another.
Re: startup getmainargs
In Windows, DLLs have the ability to have some "initialization code" that is run at load time, and the executable has msvcrt.dll as one of the DLLs that needs to be loaded, so that is where the C library has the first chance of initialization. As far as I know it doesn't have the ability to directly call main() from there - control returns to the OS and then the OS executes the entry point of the executable itself (which isn't main() - the parameters aren't right for that).Octocontrabass wrote: ↑Fri Jun 13, 2025 11:28 pmA standard C program has no setup code, so the C standard library doesn't need to give you that chance.
I was thinking more along the lines of having the entry point be inside (the equivalent of) msvcrt.dll. This is actually how dynamic linking works in Linux: dynamically linked ELF executables specify that ld-linux.so contains the entry point. (I'm not sure how you'd make this work for both dynamic linking and the C standard library at the same time.)
Universal across all compilers and linkers worldwide. You don't need special DLL/library facilities. The simplest linker - already existing - has the ability to call some arbitrary code with an arbitrary parameter. Which is all PDOS-generic OS and apps are dependent on existing. If you want to be pedantic, rwx memory is a requirement too, which prevents me from running under MacOS. I would need to replace MacOS for PDOS-generic to work on that hardware. Or in more practical terms, I need to run a VM to give me rwx memory.
Well - in my case both the OS and the apps are up for grabs. I have already encountered a problem with my original design so something needs to change. Well - there isn't a problem if I just stick to PDOS-generic apps. But now I am trying to branch into - let's say conceptually - PDOS-generic apps plus certain traditional MSDOS apps that use INT 21H - on an 8086 or 80286. "certain" being I have a scheme to tell the MSDOS app to not directly do an INT 21H - I will provide a callback function and you need to use that whenever you want to do an int86x(), or int86() or int21() - all of those are literally up for grabs because I haven't yet done MSDOS interrupt overrides - I'm starting with MVS to have some experience before I tackle MSDOS. In fact, a partial Amiga clone (which went into the pseudobios) gave me some experience before I did Atari (which went into PDOS-generic, not the pseudobios) - so that I'm ready for the quite challenging MVS. To open a file in MVS I need to provide an assembler "exit" (that gets called back), and that will need to be in low memory, but my app may be in high memory, so I haven't yet proven that I can actually do most of that in C with some generic assembler.As far as I know, no such thing exists. There are tradeoffs and compromises, and what works best for one OS might not be the right fit for another.
But bottom line - for MSDOS, to override one or all of those interrupt functions - what should the entry point of the executable be - ie the C startup code? For both a PDOS-generic app (with the OS exporting a C library) and for a modified-traditional MSDOS program (with the C library embedded - suitable to run under genuine MSDOS - but still able to run under PDOS-generic without doing a real INT instruction - it does a callback instead)?
EDIT: Actually, the 80286 - or PM16 - also doesn't give me rwx memory like I need it (I am forced to create a CS and DS alias) - but the 8086 doesn't have that issue.
-
- Member
- Posts: 5837
- Joined: Mon Mar 25, 2013 7:01 pm
Re: startup getmainargs
I still don't get it. Startup code is OS-specific. How is something universal across all compilers and linkers supposed to help you when the code itself will never be universal?
That's up to you. You're the one writing the C standard library, so you get to decide what it does before it calls main().
Re: startup getmainargs
The OS is PDOS-generic. It is portable anywhere. It doesn't require the linker to support DLLs or anything special - anywhere.Octocontrabass wrote: ↑Sat Jun 14, 2025 10:07 pmI still don't get it. Startup code is OS-specific. How is something universal across all compilers and linkers supposed to help you when the code itself will never be universal?
The apps are PDOS-generic apps. Also portable everywhere. The C code is the same - everywhere. Including the C runtime library and startup code. Or if you want to be pedantic, the sole exception is setjmp/longjmp which needs some assembler code for each different processor.
This already exists and is already working and proven on different machines including mainframes and 80386.
However, that limits me to running PDOS-generic apps.
I now have a scheme that would allow me to run (certain - constructed a particular way) MSDOS apps too. That would allow me to have a flavor of PDOS-generic that is a partial MSDOS clone. And that would allow me to produce MSDOS executables that run under both real MSDOS and my mini-MSDOS clone.
You can replace MSDOS above with Atari, Amiga, MVS etc. I don't mind having #ifdefs to produce these different mini-clones. But I am having trouble working out what should ideally happen between the OS loading an executable and reaching main().
In the case of MVS at least, there are two different start() functions that would be run. One is a recursive call into the OS's own startup routine in preparation for more files being opened so that it knows who owns them. And the other is a quite different startup routine to open stdout (SYSPRINT) etc according to the MVS standard. Both are the same function, which you can find here:
https://sourceforge.net/p/pdos/gitcode/ ... ib/start.c
Under different #ifdefs.
Currently I have a genmain and I call the main() function myself with argc/argv. But I believe I need to alter that to do a standard call to the MVS executable, with very different parameters.
And I'm looking for a clean design for this - preferably from computer science - before I start churning out more mini-clones.
EDIT: It is possible that I am incorrectly combining two different start() concepts into a single function and it is starting to bite, and I need to separate them out.
-
- Member
- Posts: 451
- Joined: Tue Apr 03, 2018 2:44 am
Re: startup getmainargs
main is the entry to your program as defined by the C standard library. It is called, as noted, by the startup code in the C runtime.kerravon wrote: ↑Sun Jun 15, 2025 5:07 pm Currently I have a genmain and I call the main() function myself with argc/argv. But I believe I need to alter that to do a standard call to the MVS executable, with very different parameters.
And I'm looking for a clean design for this - preferably from computer science - before I start churning out more mini-clones.
EDIT: It is possible that I am incorrectly combining two different start() concepts into a single function and it is starting to bite, and I need to separate them out.
The start point defined as the entry point in the ELF standard (or whatever EXE format you're using) is language agnostic, and just serves to tell the OS where in user code to start your application.
Such an entry point is in the C runtime for C programs (defined by crt0.o typically), in the C++ runtime for C++ programs (crt1.o typically) and Go runtime for Go programs (not familiar with layout of Go runtime.)
The Go example is interesting, as a lot of work is done on entry to the Go runtime. The Go runtime is heavily co-routine based (called goroutine in Go) and so includes scheduling code from the off, before it even reaches the Go main.
Go main is just a pre-defined go-routine, called by the Go runtime, like any other goroutine.
C++ also does a lot of work potentially before calling main, as it needs to run all the global constructors.
But the point is, the OS entry point is independent of the language used to implement the application. The language is opaque to the OS.
C/C++ and Go main entry points are constructs of the respective run times.
-
- Member
- Posts: 5837
- Joined: Mon Mar 25, 2013 7:01 pm
Re: startup getmainargs
So, not universal. The target is your OS, and you're looking for something that relies on the smallest possible subset of compiler and linker features so it will work with any compiler and linker that can produce binaries for your OS.
Now you're aiming for binary compatibility with existing OSes. You need different startup code for each OS, there's no single "ideal" that will work everywhere. There may even be some OSes where you can't write all of the startup code in C because the OS itself doesn't follow the C ABI.
Re: startup getmainargs
Depends what you call "universal". Any C90 compiler and linker will work with my OS. I provide the C runtime library myself though - but again - the only thing that changes is the setjmp/longjmp code. PDOS-generic apps use the exact same C code. PDOS-generic OS uses the exact same C code too. Regardless of hardware/compiler. Only if there is a new CPU do I need to update the setjmp/longjmp code. There isn't even separate ifdefs required for the code - in either the C library or OS - no matter what the hardware. PDOS-generic OS and apps are universal (hardware-wise). Even on the 8086 - so long as I use the huge memory model - exact same code. The only exception code that would be required is if I don't have rwx memory, in which case I can't support it at all, or I need exception code in the executable loader or potentially elsewhere. This would be the case for PM16 for example. Even using huge memory model with PM16 isn't enough. I need to have aliases to get cs and ds to point to the same memory. Other environments that deny rwx memory may require different solutions.Octocontrabass wrote: ↑Mon Jun 16, 2025 1:17 pmSo, not universal. The target is your OS, and you're looking for something that relies on the smallest possible subset of compiler and linker features so it will work with any compiler and linker that can produce binaries for your OS.
So that's what I'm calling "universal".
As I target other OSes, e.g. Atari or MVS - yes, they are expecting specific registers to be set, so my app needs some assembler code to accept those registers and put them on the stack ready to call the C code. And because of that, my OS also needs to set those same registers with special assembler code. I don't have a problem with that. That is well-defined.Now you're aiming for binary compatibility with existing OSes. You need different startup code for each OS, there's no single "ideal" that will work everywhere. There may even be some OSes where you can't write all of the startup code in C because the OS itself doesn't follow the C ABI.
And yes, there is OS-specific C startup code too. E.g. my MVS executables need to do some "weird" opening of DD SYSPRINT. This is also well-defined and straightforward.
Well, even with the above, there is still one thing that isn't straightforward. My PDOS-generic OS-variant that supports MVS - even JUST supporting MVS - forgetting PDOS-generic apps - still needs two different calls to what I call "__start". The OS does one to its own C library (which it exports - that's right - apps can use the OS's C library - code and data - directly - many people may not like that design, but it's what I want). This call will increment the "runnum" (run number), so that I know which files were opened (regardless of mechanism) during this "recursive call to start". That way, when the application terminates, it will close just the files that were opened during the running of this executable.
So that recursive call to start - all happening BEFORE executing the application, is done with PDOS-generic code which has no "weird" things like SYSPRINT being opened. It's not a concept in PDOS-generic OS. At least not at this stage. There will be a series of SVC (INT/trap) that will need to be handled by the OS, but I already know how to do that - that's straightforward.
So there is already a bit of complication. I'm recursively calling start to prepare the OS, and then when the application starts, there is another call to a different flavor of start (behind ifdefs), that is suitable for an MVS environment. So that's a separate compile and link - for the app. And the C library for the MVS app is behind ifdefs too.
The real complication comes when I now try to support "modified PDOS-generic apps". So these won't do SVCs - even fake SVCs. The C library won't even be in the app itself - it shares the PDOS-generic OS C library (both code and data).
And this "modified app" will have to cope with special registers/assembler code at the entry point. That's not an issue. I know how to do that. That's straightforward.
The problem is, I still have those 2 distinct calls to start. And with traditional PDOS-generic apps, it used to only be one start call, and it was the app that did it. PDOS-generic OS exports the entire C library (in a structure), including the internal "start". And the PDOS-generic app is expected to do a callback to that start routine (in the OS) so that the runnum can be identified and the files that are opened appropriately tagged so that they can be cleaned up when the app ends.
So what used to be a nice neat single call which has worked fine for years and I was perfectly happy with, is now going to fail, as it gets forcibly split into two calls. Two calls to the exact same code in PDOS-generic OS. PDOS-generic OS will do one, and then the PDOS-generic app will do another.
I can have some conditional code to detect the second call. Or I can change the design so that PDOS-generic apps stop doing a call to start(). And perhaps get inspired by how msvcrt.dll instead. Or perhaps get inspired by what Computer Science recommends. Or if it doesn't already exist - invent some Computer Science recommendation. Or turn msvcrt.dll into Computer Science.
So for my MVS mini-clone I ideally want to be able to use (straightforward but custom) MVS apps, plus modified-PDOS-generic apps.
For my Windows mini-clone I ideally want to be able to use both PDOS-generic apps (modified from what they currently look like or not), or msvcrt.dll apps - and msvcrt.dll isn't straightforward either. There are complications due to the fact that on real Windows there is a real msvcrt.dll that has some DLL startup code. But on PDOS-generic OS-with-msvcrt.dll-support there is no actual msvcrt.dll - once again, the OS just exports its own C library to satisfy the msvcrt app's needs.
The Windows mini-clone is all working, with a ridiculously small amount of code - like 100k or something - to create a Windows clone on a UEFI system (or Linux system, user-mode PDOS-generic OS, basically).
But it's quite difficult for me to understand/remember how that 100k executable manages to do that. I got it to work first - to see if it worked or whether I was missing some concept - and ask questions later.
It worked.
Now I'm trying to both understand it, plus expand its scope. 100k does Windows. A bit more will give me (already has given me in fact) an Atari mini-clone. A bit more in a different direction (behind ifdefs) will give me an MVS clone (theoretically). A bit more in a different direction has already given me an Amiga mini-clone.
Basically, I guess my question is:
Given my goals (not someone else's goals), how would you advise I write a theoretical highly portable C90-based OS and apps?
And before anyone answers "that's impossible", I already have test results showing that it is possible - regardless of whether I can explain how it works - and regardless of whether I even fully understand myself.
If you tell me which bit is impossible, I'll tell you why I think it should be possible (I had a similar discussion with S/380 - people didn't believe it would work and insisted that I had my ears closed - I had to prove it working before we could have a calm discussion about how it was in fact possible to run a 31-bit application under a 24-bit OS - and no, it's not the same as a DOS extender - a DOS extender will take over the machine to service an interrupt - my 31-bit apps are handled by the same 24-bit OS and actually required a change to the hardware (emulation made this possible) to work).
And in any discussions, it's not "should be possible", it's likely "already proven".
So we can have a calm discussion about how to design a "portable OS".
That's my question. How do you design a portable OS? And how do you extend it to turn it into an Atari clone? Let's start with Atari. And then how do you extend it into a Windows clone? And then hopefully MVS will fall into place.
For the purposes of this conversation, you can assume that I'm willing to throw the entire last 30 years of PDOS development (3 rewrites already) in the bin and start afresh.
Also note that I am bringing my own C90 library to the table, and I'm happy to rewrite from scratch too.
What hasn't changed is that I'm looking for something single-tasking, like MSDOS. And I'm not wanting virtual memory either - like MSDOS. And I want to support the 8086 too - like MSDOS. And I'm looking for something simple - like MSDOS. And I'm looking for a small KB executables size - like MSDOS (easily fits on a 360k floppy - talking just the kernel/command prompt here). And written in C90 - not like MSDOS. And works on the 68000 - not like MSDOS, but like Atari.
Those are my goals. I perfectly understand that those are not other people's goals, and I'm not arguing that my goals are better than yours - not saying anything like that at all.
But I would like some help with my goals. I want a clean design - for the above goals, that would make a Computer Science professor happy if he/she looked at the design and/or the code.
Thanks in advance for any help.
-
- Member
- Posts: 5837
- Joined: Mon Mar 25, 2013 7:01 pm
Re: startup getmainargs
How? Don't the program binaries need to be in a format your OS supports?
I'm not sure I understand your goals. The "portable" part of a C90 application is everything that happens inside main(). Everything outside of that - including the C standard library itself - is customized for the target OS and hardware. The final binary is not meant to be portable.
A C standard library is considered "portable" if there is a clear separation between the platform-independent parts and the platform-dependent parts. The platform-dependent parts must be implemented separately for each platform. (I'm using "platform" to refer to both the OS and the hardware. In reality, there's usually further separation between the two. For the OS kernel, the platform consists of firmware and hardware.)
You're trying to make application binaries that will run on at least two separate OSes. Normally this is accomplished by implementing one OS's APIs on the other. What you're suggesting is instead making the application adapt itself to different OSes. That's certainly possible, but it means now you need two copies of the platform-dependent code in your application binary and some way to select between them at runtime. (And your OS must still implement enough of the other OS's APIs to launch the polyglot application, since you're limited to build tools that only target the other OS. And it only works for your special polyglot applications.)
Changing the hardware means it's a new platform. That's still an impressive achievement, but it sounded like your goal was to run your applications on the original platform, and you haven't done that.
The best way to make a clean design is to plan ahead. That's what you're doing now, so you're on the right track.
Re: startup getmainargs
Thanks a lot for your excellent reply!
And you are correct - there is another "unstated assumption" that I didn't realize I was operating with. To me, pdld (a public domain linker) is "free" (I don't have to write any of it - may have made some minor changes - can't remember). And also it is not part of the OS that I have in mind. What I have in my mind is the chain that gets loaded into memory at runtime. So - ignoring the pseudobios I expect to be available one way or another, I have my PDOS-generic OS (generic/pdos.c), then I have the command processor (generic/pcomm.c), both of which use the C library (pdpclib - and I'm only thinking of the defines PDOS386 - a misnomer, I think it should be PDOSGENCOMMON or somesuch, PDOSGEN - for apps and PDOSGENOS - for the OS - it's a bit of a mess - I got it to work but I hardly understand it and need to revisit it - in start.c I tried to document things and ended up with "I give up" - literally in the comments). And that's everything in memory and you can then run a "hello world" PDOS-generic app.
So is that chain portable? Yes - other than setjmp/longjmp, as I stated, which needs to be adjusted to any new CPU.
However, I also stated that I can use any existing compiler/linker. That needs qualification. I actually need the other platform to provide a compiler, assembler and linker. That arms me with C90. I can then bring my OWN entire C90 ecosystem to the table. That involves using the object code from the "new platform" assembler, and pdld needs to be updated to be able to produce a.out or ELF or PE output executables from that ("new") object code format. The xar archiver may need modifications too, if it is a new format. Normally the "new platform" is actually some existing gcc toolchain, so it outputs ELF object code, so no change is required. And for the purposes of this conversation, I am expecting the output executable format from pdld to be the simple a.out format, as I don't have complicated DLLs in my simple OS. And there aren't symbols in the a.out either. So PDOS-generic OS already knows how to load a.out. There may be a temptation to change the ID string, but that's optional. I can't think of anything that needs to change for a new platform.
What I'm expecting is that a 68000 PDOS-generic app - built with my ecosystem - will run on a 68000 PDOS-generic OS - built with my ecosystem.
It is portable at the source code level - totally portable - everything - except setjmp/longjmp for each type of CPU.
I was going to say that what you said was not correct. The application binaries will only run on one example OS, the Atari. If I have an Atari clone, I don't consider that to be a "separate OS". There can be an infinite number of clones, and the binary just needs to follow what is common between all clones. And I think you have teased out another "unstated assumption". I am redefining the definition of "Atari" before "letting the clones loose" (ie lots of people can compete in making (subset) Atari clones).
In the case of the Atari, you are expected to follow the "a1 standard" (which I just made up).
In the case of the Amiga, you are expected to follow the "d7 standard" (which I also made up).
MVS apps will need to follow the "R1 standard" (which I haven't yet made up, but I have a rough idea).
None of the above are set in stone - this forum post could potentially change that, but for now, let's assume they are set in stone. And all apps are required to follow these standards. Which ideally should have been set by "Computer Science" back in the 80s for the first 2, or back in the 1960s for MVS. The fact that "Computer Science" was "tardy" doesn't bother me.
The fact that "tardiness" means that the entire body of existing Atari, Amiga and MVS apps - even text-based apps - is suddenly rendered "invalid" doesn't bother me either.
A simple recompile of your C90 application will fix the problem.
The fact that you don't even have a C90 application - you've used extensions - so no apps will work - even with a recompile - because they're not strictly C90 - rendering almost everything invalid - doesn't bother me.
So - very unusual "requirements".
So trap1() exists in my Atari clone. I simply don't have the 68000 trap vector populated because I don't use it. Perhaps one day I can do that though, to allow a non-a1-conforming Atari application - that does a real trap #1, to work. However, that would not be something I wish to implement at the moment. It could be considered though - to avoid going down a road that ends with a dead end at that future date.
This stopped me in my tracks and made me think.Octocontrabass wrote: ↑Fri Jun 20, 2025 9:12 pmHow? Don't the program binaries need to be in a format your OS supports?
And you are correct - there is another "unstated assumption" that I didn't realize I was operating with. To me, pdld (a public domain linker) is "free" (I don't have to write any of it - may have made some minor changes - can't remember). And also it is not part of the OS that I have in mind. What I have in my mind is the chain that gets loaded into memory at runtime. So - ignoring the pseudobios I expect to be available one way or another, I have my PDOS-generic OS (generic/pdos.c), then I have the command processor (generic/pcomm.c), both of which use the C library (pdpclib - and I'm only thinking of the defines PDOS386 - a misnomer, I think it should be PDOSGENCOMMON or somesuch, PDOSGEN - for apps and PDOSGENOS - for the OS - it's a bit of a mess - I got it to work but I hardly understand it and need to revisit it - in start.c I tried to document things and ended up with "I give up" - literally in the comments). And that's everything in memory and you can then run a "hello world" PDOS-generic app.
So is that chain portable? Yes - other than setjmp/longjmp, as I stated, which needs to be adjusted to any new CPU.
However, I also stated that I can use any existing compiler/linker. That needs qualification. I actually need the other platform to provide a compiler, assembler and linker. That arms me with C90. I can then bring my OWN entire C90 ecosystem to the table. That involves using the object code from the "new platform" assembler, and pdld needs to be updated to be able to produce a.out or ELF or PE output executables from that ("new") object code format. The xar archiver may need modifications too, if it is a new format. Normally the "new platform" is actually some existing gcc toolchain, so it outputs ELF object code, so no change is required. And for the purposes of this conversation, I am expecting the output executable format from pdld to be the simple a.out format, as I don't have complicated DLLs in my simple OS. And there aren't symbols in the a.out either. So PDOS-generic OS already knows how to load a.out. There may be a temptation to change the ID string, but that's optional. I can't think of anything that needs to change for a new platform.
Without doubt - that is ALLOWED. Noone should EXPECT the C standard library itself to be portable. However, it is anyway (or rather - can be - in the situation I am describing).I'm not sure I understand your goals. The "portable" part of a C90 application is everything that happens inside main(). Everything outside of that - including the C standard library itself - is customized
The target OS is not changing - I'm only discussing PDOS-generic at the moment, so as I switch to a new processor, that doesn't change - except for setjmp/longjmpfor the target OS
Yes, just the CPU matters, and just in that one isolated spot - setjmp/longjmp.and hardware.
I'm not expecting a 68000 binary to be portable to an 80386.The final binary is not meant to be portable.
What I'm expecting is that a 68000 PDOS-generic app - built with my ecosystem - will run on a 68000 PDOS-generic OS - built with my ecosystem.
It is portable at the source code level - totally portable - everything - except setjmp/longjmp for each type of CPU.
In my case - ignoring the other targets (which are of zero interest in this conversation - for now at least) I have added to PDPCLIB - the only separation is setjmp/longjmp. My C library is strictly C90. Zero extensions. It turns out that absolutely everything is - or can be - portable - except for setjmp/longjmp.A C standard library is considered "portable" if there is a clear separation between the platform-independent parts and the platform-dependent parts. The platform-dependent parts must be implemented separately for each platform. (I'm using "platform" to refer to both the OS and the hardware. In reality, there's usually further separation between the two. For the OS kernel, the platform consists of firmware and hardware.)
Ok, we are now moving away from the strictly portable PDOS-generic toolchain, and introducing things like the Atari.You're trying to make application binaries that will run on at least two separate OSes.
I was going to say that what you said was not correct. The application binaries will only run on one example OS, the Atari. If I have an Atari clone, I don't consider that to be a "separate OS". There can be an infinite number of clones, and the binary just needs to follow what is common between all clones. And I think you have teased out another "unstated assumption". I am redefining the definition of "Atari" before "letting the clones loose" (ie lots of people can compete in making (subset) Atari clones).
In the case of the Atari, you are expected to follow the "a1 standard" (which I just made up).
In the case of the Amiga, you are expected to follow the "d7 standard" (which I also made up).
MVS apps will need to follow the "R1 standard" (which I haven't yet made up, but I have a rough idea).
None of the above are set in stone - this forum post could potentially change that, but for now, let's assume they are set in stone. And all apps are required to follow these standards. Which ideally should have been set by "Computer Science" back in the 80s for the first 2, or back in the 1960s for MVS. The fact that "Computer Science" was "tardy" doesn't bother me.
The fact that "tardiness" means that the entire body of existing Atari, Amiga and MVS apps - even text-based apps - is suddenly rendered "invalid" doesn't bother me either.
A simple recompile of your C90 application will fix the problem.
The fact that you don't even have a C90 application - you've used extensions - so no apps will work - even with a recompile - because they're not strictly C90 - rendering almost everything invalid - doesn't bother me.
So - very unusual "requirements".
I do that too. Preparation for an Atari (original standard) trap is done. But at the very last millisecond, since I'm using the a1 standard, if PDOS-generic OS was detected at application startup time, I won't issue the trap #1. I will instead do a callback to a trap1() provided by PDOS-generic OS.Normally this is accomplished by implementing one OS's APIs on the other.
So trap1() exists in my Atari clone. I simply don't have the 68000 trap vector populated because I don't use it. Perhaps one day I can do that though, to allow a non-a1-conforming Atari application - that does a real trap #1, to work. However, that would not be something I wish to implement at the moment. It could be considered though - to avoid going down a road that ends with a dead end at that future date.
Yes, correct - however, I would argue that the "two copies" don't really exist. I am redefining the original Atari standard so that even real Atari TOS could choose to tell an application "don't do a real trap - for some reason I'm not in the mood to handle a trap - and you are required to obey my directive". The same applies to MSDOS. The app must obey the "new MSDOS standard" that allows MSDOS to tell the app to not do a real INT 21H. We actually have the source code for MSDOS 4.0, so this could even become a "reality" for some definition of "reality".What you're suggesting is instead making the application adapt itself to different OSes. That's certainly possible, but it means now you need two copies of the platform-dependent code in your application binary and some way to select between them at runtime. (And your OS must still implement enough of the other OS's APIs to launch the polyglot application, since you're limited to build tools that only target the other OS. And it only works for your special polyglot applications.)
Yes I can. It took a few decades to figure out AMODE/RMODE, but now my applications work on MVS/380 on S/380, and also on 24-bit MVS 3.8j, and also on 31-bit MVS/XA, and also on modern z/OS. I realized that instead of my application demanding the AMODE and RMODE I required, I instead need the app to detect what it was given, and to gracefully adapt to whatever it was given.Changing the hardware means it's a new platform. That's still an impressive achievement, but it sounded like your goal was to run your applications on the original platform, and you haven't done that.
Thanks for that encouragement that I am doing things properly this time round. My documentation for PDOS used to say something along the lines of "I don't know what I'm doing - I need YOUR help", but sort of noone really responded to that. Maybe Alica Okana from Slovakia did to some extent. Later I deleted that because I was happy with the design now and didn't want to change it. But now it's (sort of) up for grabs again.