startup getmainargs

Discussions on more advanced topics such as monolithic vs micro-kernels, transactional memory models, and paging vs segmentation should go here. Use this forum to expand and improve the wiki!
Post Reply
kerravon
Member
Member
Posts: 307
Joined: Fri Nov 17, 2006 5:26 am

startup getmainargs

Post by kerravon »

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.
Octocontrabass
Member
Member
Posts: 5823
Joined: Mon Mar 25, 2013 7:01 pm

Re: startup getmainargs

Post by Octocontrabass »

kerravon wrote: Thu Jun 12, 2025 5:11 pmAnd 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 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().
kerravon wrote: Thu Jun 12, 2025 5:11 pmSpecifically you do a call to get the arguments and then you execute main.
"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.
kerravon wrote: Thu Jun 12, 2025 5:11 pmThe startup code - if any - would need to exist in getmainargs.
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.
kerravon
Member
Member
Posts: 307
Joined: Fri Nov 17, 2006 5:26 am

Re: startup getmainargs

Post by kerravon »

Octocontrabass wrote: Fri Jun 13, 2025 1:03 pm
kerravon wrote: Thu Jun 12, 2025 5:11 pmAnd 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 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().
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.

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.
kerravon wrote: Thu Jun 12, 2025 5:11 pmSpecifically you do a call to get the arguments and then you execute main.
"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.
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.
kerravon wrote: Thu Jun 12, 2025 5:11 pmThe startup code - if any - would need to exist in getmainargs.
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.
Sure.
Octocontrabass
Member
Member
Posts: 5823
Joined: Mon Mar 25, 2013 7:01 pm

Re: startup getmainargs

Post by Octocontrabass »

kerravon wrote: Fri Jun 13, 2025 8:16 pmHowever, having main() as an entry point means there is no chance for some setup code in the executable to be run.
A standard C program has no setup code, so the C standard library doesn't need to give you that chance.
kerravon wrote: Fri Jun 13, 2025 8:16 pmYou 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.
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.)
kerravon wrote: Fri Jun 13, 2025 8:16 pmI want something that is universal C90.
I'm not sure I understand what you mean by "universal". Startup code is OS-specific.
kerravon wrote: Fri Jun 13, 2025 8:16 pmI 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.
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.
kerravon
Member
Member
Posts: 307
Joined: Fri Nov 17, 2006 5:26 am

Re: startup getmainargs

Post by kerravon »

Octocontrabass wrote: Fri Jun 13, 2025 11:28 pm
kerravon wrote: Fri Jun 13, 2025 8:16 pmHowever, having main() as an entry point means there is no chance for some setup code in the executable to be run.
A standard C program has no setup code, so the C standard library doesn't need to give you that chance.
kerravon wrote: Fri Jun 13, 2025 8:16 pmYou 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.
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.)
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).
kerravon wrote: Fri Jun 13, 2025 8:16 pmI want something that is universal C90.
I'm not sure I understand what you mean by "universal". Startup code is OS-specific.
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.
kerravon wrote: Fri Jun 13, 2025 8:16 pmI 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.
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.
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.

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.
Post Reply