/***************************************************************************** * FILE: loadprg.c * * * * DESC: * * - loader for coff/a.out programs * * - set args,environment * * - load text,data (if not DPMI 1.0) * * * * Copyright (C) 1993,1994 * * Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld * * email: rainer@mathematik.uni-bielefeld.de * * * *****************************************************************************/ #include #include "DPMI.H" #include "DPMI10.H" #include "PRINTF.H" #include "RMLIB.H" #include "PROCESS.H" #include "FS.H" #include "GNUAOUT.H" #include "LOADPRG.H" #include "COPY32.H" #include "START32.H" #include "CDOSX32.H" #include "RSX.H" #include "DOSERRNO.H" static int skip_exe_hdr(int filehandle, DWORD * headoff, NEWPROCESS *p) { struct exe_hdr exehdr; struct emx_hdr2 emxhdr; rm_read(filehandle, &exehdr, sizeof(struct exe_hdr)); if (exehdr.signatur == 0x5a4d) { /* falls exe-kopf */ *headoff = ((DWORD) exehdr.hdr_para) * 16; rm_lseek(filehandle, *headoff, SEEK_SET); rm_read(filehandle, &emxhdr, sizeof(emxhdr)); if (memcmp(emxhdr.sig, "emx", 3) == 0) { *headoff = *(DWORD *) emxhdr.next_hdr; if (emxhdr.option[0]) { char *s = emxhdr.option; for (; *s != '\0'; ++s) { while (*s == ' ') ++s; if (*s == '-') { s = scan_for_option(++s, p); } else break; } } } else if (memcmp(emxhdr.sig, "rsx", 3) == 0) goto fail; /* prevent loading rsx32.exe as a.out */ else { /* not a emx file */ long new_off; rm_lseek(filehandle, 0x3C, SEEK_SET); rm_read(filehandle, &new_off, sizeof(long)); if (new_off) { char pe_sig[4]; rm_lseek(filehandle, new_off, SEEK_SET); rm_read(filehandle, pe_sig, sizeof(pe_sig)); if (pe_sig[0]) *headoff = new_off + 4; } else { /* djgpp */ *headoff = (DWORD) exehdr.high * 512L; if (exehdr.low) *headoff += (DWORD) exehdr.low - 512L; } } } /* exe files */ if (rm_lseek(filehandle, *headoff, SEEK_SET) == -1L) goto fail; return 0; fail: *headoff = 0; rm_lseek(filehandle, 0, SEEK_SET); return -1; } /* ** arguments and environment at process start ** ** environment and argument strings ** argv[] ** envp[] ** pointer to env[0] ** pointer to argv[0] ** int argc ** <- ESP */ int argvenv(int argc, char **argv, int envc, char **env, NEWPROCESS * proc) { int i; DWORD len, stkp; DWORD *vectors; UINT count = 3; /* 0=argc 1=argv 2=env */ vectors = (DWORD *) iobuf; stkp = proc->stackp32; /* store env strings in user stack, built vectors */ for (i = 0; i < envc; i++) { len = (DWORD) (UINT) strlen(env[i]) + 1; stkp -= len; stkp &= ~3L; /* align4 */ cpy16_32(proc->data32sel, stkp, env[i], len); vectors[count++] = stkp; } vectors[count++] = 0; /* last is a NULL pointer */ /* store arg strings in user stack, built vectors */ for (i = 0; i < argc; i++) { len = (DWORD) (UINT) strlen(argv[i]) + 1; stkp -= len; stkp &= ~3L; cpy16_32(proc->data32sel, stkp, argv[i], len); vectors[count] = stkp; count++; /* for emx: add flag */ stkp -= 1; put_user_byte(proc->data32sel, stkp, 0x80); } vectors[count++] = 0; /* last is a NULL pointer */ stkp &= ~3L; len = (DWORD) (count * sizeof(long)); stkp -= len; vectors[0] = argc; vectors[1] = stkp + (4L + envc) * sizeof(long); /* & vectors[3+nenvp+1] */ vectors[2] = stkp + 3 * sizeof(long); /* & vectors[3] */ cpy16_32(proc->data32sel, stkp, vectors, len); if (proc->p_flags & PF_EMX_FILE) stkp += 3 * 4; proc->stackp32 = stkp; return 0; } void cpy_exename_to_stack(NEWPROCESS *proc, char *name) { int len = strlen(name) + 1; long name_pos = proc->stackp32 - (long) (len + 2 * sizeof(DWORD)); proc->stackp32 -= sizeof(DWORD); store32(proc->data32sel, proc->stackp32, name_pos); proc->stackp32 -= sizeof(DWORD); store32(proc->data32sel, proc->stackp32, (long) len); proc->stackp32 -= (long) len; cpy16_32(proc->data32sel, proc->stackp32, name, (long) len); } int readin_file(short handle, short r_ds, long r_edx, long count) { long bytes; int rc; while (count > 0) { bytes = (count <= IOBUF_SIZE) ? count : (DWORD) IOBUF_SIZE; rc = rm_read(handle, iobuf, (short) bytes); cpy16_32(r_ds, r_edx, iobuf, rc); if (bytes != rc) break; count -= bytes; r_edx += bytes; } return 0; } /* ** ** RSX program layout: ** ** ** DPMI 0.9 : fixed stack ** never ending heap ** ** emx style ** |-------------------------------------------------------------- ** |stack| code | data/bss | stack,if>64KB | heap -> ... ** |-------------------------------------------------------------- ** 0 ^64 KB ^(n x 64KB) ** ** ** old djgpp style ** |-------------------------------------------------------------- ** | | code | stack | data/bss | heap -> ... ** |-------------------------------------------------------------- ** 0 ^4K ^0x400000 ** ** djgpp style 1.11 ** |-------------------------------------------------------------- ** | code | data/bss | stack | heap -> ... ** |-------------------------------------------------------------- ** 0 ^ 4 Kb align ^ ** ** ** ** DPMI 1.0 : address room = 64 MegaBytes ** ** |--------------------------------------------...-----------------------| ** | | code | | data/bss | heap -> <- stack | mappings | ** | | | | | | DOS 1MB | ** |--------------------------------------------...-----------------------| ** 0 ^60 64 ** */ #define SHORT_EMX_STACK (0x10000L-0x1000L) /* 64 KB - one R/O page */ #define DEFAULT_STACK (0x40000L) /* 256 KB */ #define TEXT 0 #define DATA 1 #define BSS 2 int load_protected_program(char *filename, NEWPROCESS * proc) { FILEHDR file_hdr; AOUTHDR aout_hdr; SCNHDR scnd_hdr[3]; DWORD tdbsegm, stacksegm; DWORD headoff; UINT stack32sel; int fhandle; int use_dpmi10; if ((fhandle = rm_open(filename, RM_O_RDONLY | RM_O_DENYWR)) == -1) return doserror_to_errno(_doserrno); /* skip exe-header, return correct offset in file */ headoff = 0; skip_exe_hdr(fhandle, &headoff, proc); /* read file header */ rm_read(fhandle, &file_hdr, sizeof(file_hdr)); if (file_hdr.f_magic == 0x14C) { /* COFF header */ rm_read(fhandle, &aout_hdr, sizeof(aout_hdr)); rm_lseek(fhandle, headoff + sizeof(file_hdr) + file_hdr.f_opthdr, 0); rm_read(fhandle, scnd_hdr, sizeof(scnd_hdr)); if ((scnd_hdr[TEXT].s_scnptr & 0xFF) == 0xA8) { /* DJGPP */ scnd_hdr[TEXT].s_vaddr &= ~0xFFL; scnd_hdr[TEXT].s_scnptr &= ~0xFFL; /* align */ scnd_hdr[TEXT].s_size += 0xa8L; proc->p_flags |= PF_DJGPP_FILE; } else { DWORD image_base; rm_lseek(fhandle, headoff + sizeof(file_hdr) + file_hdr.f_opthdr, 0); rm_read(fhandle, &image_base, 4); if (image_base == 0x400000L) proc->p_flags |= PF_TNT_FILE; printf("image base %lX\n", image_base); } } else if (file_hdr.f_magic == 0x10B) { GNUOUT gnu_hdr; rm_lseek(fhandle, headoff, 0); rm_read(fhandle, &gnu_hdr, sizeof(gnu_hdr)); aout_hdr.magic = 0x10B; aout_hdr.tsize = gnu_hdr.a_text; aout_hdr.dsize = gnu_hdr.a_data; aout_hdr.bsize = gnu_hdr.a_bss; aout_hdr.entry = gnu_hdr.a_entry; scnd_hdr[TEXT].s_size = gnu_hdr.a_text; scnd_hdr[DATA].s_size = gnu_hdr.a_data; scnd_hdr[BSS].s_size = gnu_hdr.a_bss; if (gnu_hdr.a_entry == 0x10000L) { /* EMX STYLE */ scnd_hdr[TEXT].s_vaddr = 0x10000L; scnd_hdr[DATA].s_vaddr = 0x10000L + ((gnu_hdr.a_text + 0xFFFFL) & ~0xFFFFL); scnd_hdr[BSS].s_vaddr = scnd_hdr[DATA].s_vaddr + gnu_hdr.a_data; scnd_hdr[TEXT].s_scnptr = 1024; scnd_hdr[DATA].s_scnptr = 1024 + gnu_hdr.a_text; proc->p_flags |= PF_EMX_FILE; } else { /* OLD DJGPP STYLE */ scnd_hdr[TEXT].s_vaddr = 0x400000L; scnd_hdr[DATA].s_vaddr = 0x400000L + ((gnu_hdr.a_text + 0x3FFFFFL) & ~0x3FFFFFL); scnd_hdr[BSS].s_vaddr = scnd_hdr[DATA].s_vaddr + gnu_hdr.a_data; scnd_hdr[TEXT].s_scnptr = 0; scnd_hdr[DATA].s_scnptr = (gnu_hdr.a_text + 0xFFFL) & ~0xFFFL; proc->p_flags |= PF_DJGPP_FILE; } } else { /* not a valid header */ rm_close(fhandle); return EMX_ENOEXEC; } proc->filehandle = (long) fhandle; proc->text_off = headoff + scnd_hdr[TEXT].s_scnptr; proc->data_off = headoff + scnd_hdr[DATA].s_scnptr; proc->text_start = scnd_hdr[TEXT].s_vaddr; proc->text_end = scnd_hdr[TEXT].s_vaddr + scnd_hdr[TEXT].s_size; proc->bss_start = scnd_hdr[BSS].s_vaddr; proc->bss_end = scnd_hdr[BSS].s_vaddr + scnd_hdr[BSS].s_size; proc->data_start = scnd_hdr[DATA].s_vaddr; proc->data_end = (proc->bss_end + 4095L) & ~4095L; proc->entry = aout_hdr.entry; /* compute size of text-data-bss and stack segment for AllocMem() */ tdbsegm = proc->data_end; if (opt_stackval) stacksegm = (DWORD) opt_stackval *1024; else stacksegm = DEFAULT_STACK; if (proc == &RSX_PROCESS) { /* emu don't need much stack */ stacksegm = SHORT_EMX_STACK; use_dpmi10 = 0; } else use_dpmi10 = (dpmi10) ? 1 : 0; if (use_dpmi10) proc->p_flags |= PF_USEDPMI10; /* look for empty space for stack */ if (aout_hdr.entry == 0x10000L && stacksegm <= SHORT_EMX_STACK) { stacksegm = 0; /* place stack in the first 64KB segment */ proc->stack_top = proc->text_start; proc->stack_down = 0x1000L; } else if (aout_hdr.entry == 0x1020L && stacksegm <= (proc->data_start - proc->text_end)) { stacksegm = 0; /* place stack between code and data */ proc->stack_top = proc->data_start; proc->stack_down = proc->text_end + 0x1000; } else { /* put stack after data/bss */ proc->stack_top = proc->data_end + stacksegm; proc->stack_down = proc->data_end; /* sorry, work around window bug */ if ((proc->p_flags & PF_DJGPP_FILE) && proc->stack_down <= 0x11000L && proc != &RSX_PROCESS) { DWORD add_stack = 0x11000L - proc->stack_down; proc->stack_top += add_stack; proc->stack_down += add_stack; stacksegm += add_stack; } } if (use_dpmi10) { stacksegm = 0; proc->stack_top = DPMI_PRG_DATA; proc->stack_down = proc->data_end; } proc->stacksize = proc->stack_top - proc->stack_down; proc->stackp32 = proc->stack_top - 4L; proc->init_brk = proc->data_end + stacksegm; proc->brk_value = proc->init_brk; proc->pagefree = 0; /* total memory for process */ if (use_dpmi10) { proc->pagefree = DPMI_PRG_DATA - proc->membytes; proc->membytes = DPMI_PRG_ROOM; } else { proc->membytes = tdbsegm + stacksegm; /* prealloc more heap */ if (opt_memalloc) { proc->pagefree = (long) opt_memalloc * 1024; proc->membytes += (long) opt_memalloc * 1024; } else if (opt_memaccess || (proc->options & OPT_MEMACCESS)) { proc->pagefree = 0x21000; proc->membytes += 0x21000; } } /* since dosmem isn't used by DPMI we put rsx387 in dos memory */ if (proc == &RSX_PROCESS && rsx387_in_dosmem) { UINT segment, selectors; if (AllocDosMem((UINT) (proc->membytes >> 4), &segment, &selectors)) { if (AllocMem(proc->membytes, &(proc->memhandle), &(proc->memaddress))) return EMX_ENOMEM; } else { proc->memaddress = (DWORD) segment << 4; proc->memhandle = (DWORD) selectors; } } /* get memory from DPMI-host */ else if (!use_dpmi10) { if (AllocMem(proc->membytes, &(proc->memhandle), &(proc->memaddress))) return EMX_ENOMEM; } else if (AllocLinearMemory(proc->membytes, 0L, 0L, &proc->memhandle, &proc->memaddress)) return EMX_ENOMEM; /* alloc 32bit cs,ds ldt selector */ if (AllocLDT(3, &(proc->code32sel))) return EMX_EIO; proc->data32sel = proc->code32sel + sel_incr; stack32sel = proc->data32sel + sel_incr; /* fill descriptors */ SetBaseAddress(proc->code32sel, proc->memaddress); SetBaseAddress(proc->data32sel, proc->memaddress); SetBaseAddress(stack32sel, proc->memaddress); SetAccess(proc->code32sel, APP_CODE_SEL, DEFAULT_BIT); SetAccess(proc->data32sel, APP_DATA_SEL, BIG_BIT); SetAccess(stack32sel, APP_DATA_SEL | EXPAND_BIT, BIG_BIT | GRANULAR_BIT); /* allow execute data & stack (DJGPP / GDB need this) */ SetLimit(proc->code32sel, proc->membytes - 1L); if (!use_dpmi10) { if (opt_memaccess || (proc->options & OPT_MEMACCESS)) SetLimit(proc->data32sel, 0xFFFFFFFF); else SetLimit(proc->data32sel, proc->membytes - 1L); } else SetLimit(proc->data32sel, DPMI_PRG_ROOM - 1L); /* set stack expand down segment to first stack address */ SetLimit(stack32sel, proc->stack_down - 1L); /* map first DOS MB at the end of linear Addressroom (60MB) */ if (use_dpmi10 && (opt_memaccess || (proc->options & OPT_MEMACCESS))) MapDOSMemInMemoryBlock(proc->memhandle, DPMI_PRG_DATA, 256L, 0L); if (!use_dpmi10) { /* read in code */ rm_lseek(fhandle, proc->text_off, SEEK_SET); readin_file(fhandle, proc->data32sel, scnd_hdr[TEXT].s_vaddr, scnd_hdr[TEXT].s_size); /* read in data,bss */ rm_lseek(fhandle, proc->data_off, SEEK_SET); readin_file(fhandle, proc->data32sel, scnd_hdr[DATA].s_vaddr, scnd_hdr[DATA].s_size); rm_close(fhandle); /* zero bss segment */ if (scnd_hdr[BSS].s_size) bzero32(proc->data32sel, scnd_hdr[BSS].s_vaddr, scnd_hdr[BSS].s_size); } else { /* uncommit first stack page! */ WORD page = 9; ModifyPageAttributes(proc->memhandle, proc->stack_top - 4096, 1, &page); } return 0; } /* this structure that starts a core file */ struct user_area { WORD u_magic ; WORD u_reserved1 ; DWORD u_data_base ; DWORD u_data_end ; DWORD u_data_off ; DWORD u_heap_base ; DWORD u_heap_end ; DWORD u_heap_off ; DWORD u_heap_brk ; DWORD u_stack_base; DWORD u_stack_end ; DWORD u_stack_off ; DWORD u_stack_low ; DWORD u_ar0 ; DWORD u_fpvalid ; DWORD u_fpstate[27] ; DWORD u_fpstatus; DWORD u_reserved3[23]; REG386 u_regs; }; #define U_OFFSET 0x400 int write_section(short handle, short r_ds, long r_edx, long count) { long bytes; int rc; while (count > 0) { bytes = (count <= IOBUF_SIZE) ? count : (DWORD) IOBUF_SIZE; cpy32_16(r_ds, r_edx, iobuf, bytes); rc = rm_write(handle, iobuf, (short) bytes); if (bytes != rc) return -1; count -= bytes; r_edx += bytes; } return 0; } #include "PRINTF.H" int write_core(unsigned handle, NEWPROCESS *proc) { struct user_area ua; DWORD data_size; DWORD heap_size; memset(& ua, 0, sizeof(ua)); ua.u_magic = 0x10F; ua.u_ar0 = 0xE0000000L + (DWORD)(UINT)&(((struct user_area *)0)->u_regs); memcpy(& ua.u_regs, &(proc->regs), sizeof(REG386)); ua.u_data_base = proc->data_start; ua.u_data_end = proc->bss_end; /* bss not rounded */ data_size = proc->data_end - proc->data_start; /* data is page-aligned */ ua.u_data_off = U_OFFSET; ua.u_heap_base = proc->init_brk; ua.u_heap_end = (proc->brk_value + 0xFFFL) & ~0xFFFL; ua.u_heap_brk = proc->brk_value; heap_size = ua.u_heap_end - ua.u_heap_base; ua.u_heap_off = ua.u_data_off + data_size; ua.u_stack_base = proc->stack_down; ua.u_stack_end = proc->stack_top; ua.u_stack_low = proc->regs.esp; ua.u_stack_off = ua.u_heap_off + heap_size; rm_write(handle, &ua, sizeof(ua)); /* header */ memset(iobuf, 0, U_OFFSET); rm_write(handle, iobuf, U_OFFSET - sizeof(ua)); rm_lseek(handle, ua.u_data_off, 0); if (write_section(handle, proc->data32sel, ua.u_data_base, data_size)) goto bad_write; rm_lseek(handle, ua.u_heap_off, 0); if (write_section(handle, proc->data32sel, ua.u_heap_base, heap_size)) goto bad_write; rm_lseek(handle, ua.u_stack_off, 0); if (write_section(handle, proc->data32sel, ua.u_stack_low, ua.u_stack_end - ua.u_stack_low)) goto bad_write; rm_close(handle); return 0; bad_write: return -1; } int write_core_file(NEWPROCESS *proc) { int handle, ret; static char core_name[]="CORE"; handle = rm_creat(core_name, _A_NORMAL); if (handle == -1) return -1; puts("writing core file"); ret = write_core(handle, proc); rm_close(handle); /* if (ret == -1) unlink(core_name); */ return ret; }