As you mentioned vbcc, here is the vclib startup code for the i386-aros target, which I had to abandon about 10 years ago. Maybe declaring __startup_entry as global is important for the loader, but I don't remember.
Code:
#
# vbcc/AROS386 startup
# Written by Frank Wille <frank@phoenix.owl.de> 2006
#
# Version
.set VERSION,1
.set REVISION,01
.macro VBCC_VER
.byte "VBCC 0.9"
.endm
.extern __cstart
.text
.globl __startup_entry
__startup_entry:
# Entered with:
# 0(%esp) return address to DOS
# 4(%esp) argument string pointer
# 8(%esp) argument string length
# 12(%esp) SysBase pointer
movl $__save_regs,%eax
mov %esp,(%eax)
mov %ebx,4(%eax)
mov %ebp,8(%eax)
mov %esi,12(%eax)
mov %edi,16(%eax)
mov 12(%esp),%eax
mov %eax,SysBase
jmp __cstart
VBCC_VER
.type __startup_entry,@function
.size __startup_entry,.-__startup_entry
.globl __asmexit
__asmexit:
mov 4(%esp),%eax
movl $__save_regs,%edx
mov (%edx),%esp
mov 4(%edx),%ebx
mov 8(%edx),%ebp
mov 12(%edx),%esi
mov 16(%edx),%edi
ret
.type __asmexit,@function
.size __asmexit,.-__asmexit
.byte "startup V"
.byte '0'+VERSION,'.','0'+(REVISION/10),'0'+(REVISION%10),0
.lcomm __save_regs,20
.comm SysBase,4
As I am quite unexperienced in x86 assembler, I switched to C as soon as possible. Command line parsing and WB-startup follows in __cstart():
Code:
/*
** vbcc/AROS386 startup
** Written by Frank Wille <frank@phoenix.owl.de> 2006
*/
#include <dos/dosextens.h>
#include <workbench/startup.h>
#include <proto/exec.h>
#include <proto/dos.h>
struct SVar {
BPTR WbOutput;
char *ArgvBufPtr;
char *ArgvArray[1];
};
struct DosLibrary *DOSBase;
struct WBStartup *WBenchMsg,*_WBenchMsg;
BPTR _stdin,_stdout,_stderr;
static struct SVar *svar;
extern void __asmexit(int);
extern void __main(int,char **);
static int strlen(__reg("%edi") const char *) =
"\tcld\n"
"\txor\t%eax,%eax\n"
"\tmov\t%eax,%ecx\n"
"\tdec\t%ecx\n"
"\trepne\n"
"\tscasb\n"
"\tnot\t%ecx\n"
"\tlea\t-1(%ecx),%eax";
void __exit(int code)
{
if (DOSBase) {
if (svar) {
if (svar->WbOutput)
Close(svar->WbOutput);
FreeVec(svar);
}
CloseLibrary((struct Library *)DOSBase);
}
if (WBenchMsg) {
Forbid();
ReplyMsg((struct Message *)WBenchMsg);
}
__asmexit(code);
}
static void getWbMsg(struct Process *this_proc)
{
WaitPort(&this_proc->pr_MsgPort);
WBenchMsg = _WBenchMsg = (struct WBStartup *)GetMsg(&this_proc->pr_MsgPort);
}
static void startup_failed(struct Process *this_proc)
{
if (!this_proc->pr_CLI)
getWbMsg(this_proc);
__exit(RETURN_FAIL);
}
static int command_len(void)
{
char buf[1024];
if (GetProgramName(buf,1024))
return strlen(buf) + 1;
return 0;
}
void __cstart(unsigned char *argstr,int arglen)
{
struct Process *this_proc = (struct Process *)FindTask(NULL);
int argc,argc_est,len;
char **argv;
unsigned char *p;
if (!(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",39)))
startup_failed(this_proc);
/* estimate number of argv-slots */
if (this_proc->pr_CLI) {
for (argc_est=3,len=arglen,p=argstr; len>0 && *p!='\0'; len--,p++) {
if (*p <= ' ')
argc_est++;
}
len = command_len();
}
else {
argc_est = 2; /* two dummy arguments for WB-start */
arglen = 8;
len = 0;
}
if (!(svar = AllocVec(sizeof(struct SVar) +
argc_est*sizeof(char *) + len + arglen + 1,
MEMF_PUBLIC | MEMF_CLEAR))) {
startup_failed(this_proc);
}
svar->ArgvBufPtr = (char *)&svar->ArgvArray[argc_est+1];
if (this_proc->pr_CLI) {
/* started from CLI */
if (len)
GetProgramName(svar->ArgvBufPtr,len);
argv = svar->ArgvArray;
*argv++ = svar->ArgvBufPtr;
svar->ArgvBufPtr += len;
argc = 1;
/* eat trailing control characters on command line */
for (len=arglen,p=argstr+arglen-1; len>0 && *p<=' '; len--,p--);
*(p+1) = '\0';
for (p=svar->ArgvBufPtr; *argstr!='\0' && argc<argc_est; ) {
while (*argstr!='\0' && *argstr<=' ')
argstr++;
if (*argstr == '\0')
break;
argc++;
*argv++ = p;
if (*argstr == '\"') {
unsigned char c;
argstr++;
while ((c = *argstr++) != '\"') {
if (c == '\0') {
argstr--;
break;
}
else if (c == '*') { /* BCPL escape character */
switch (c = *argstr++) {
case '\0': argstr--; break;
case 'N': *p++ = '\n'; break;
case 'E': *p++ = 27; break;
default: *p++ = c; break;
}
}
else
*p++ = c;
}
}
else {
while (*argstr > ' ')
*p++ = *argstr++;
}
*p++ = '\0';
}
*argv = NULL;
argv = svar->ArgvArray;
_stdin = Input();
_stdout = Output();
if (!(_stderr = this_proc->pr_CES))
_stderr = _stdout;
}
else {
/* started from Workbench */
struct WBArg *wbarg;
getWbMsg(this_proc);
argv = (char **)WBenchMsg;
argc = 0;
if (wbarg = WBenchMsg->sm_ArgList)
CurrentDir(wbarg->wa_Lock);
/* set I/O to NIL: */
if (svar->WbOutput = Open("NIL:",MODE_OLDFILE))
_stdin = _stdout = _stderr = svar->WbOutput;
else
startup_failed(this_proc);
#if 0 /* @@@ how to do this under AROS ??? */
/* set console task, so Open("*",mode) will work */
this_proc->pr_CIS = _stdin;
this_proc->pr_COS = _stdout;
this_proc->pr_ConsoleTask = ...
#endif
}
__main(argc,argv); /* vclib init, call main() */
__exit(0); /* although __main() should never return */
}
|