/*
* dj64 - 64bit djgpp-compatible tool-chain
* Copyright (C) 2021-2024 @stsp
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
#define _PAGE_MASK (~(PAGE_SIZE-1))
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&_PAGE_MASK)
// https://github.com/vonj/snippets.org/blob/master/strrpbrk.c
static char *strrpbrk(const char *szString, const char *szChars)
{
const char *p;
char *p0, *p1;
for (p = szChars, p0 = p1 = NULL; p && *p; ++p)
{
p1 = strrchr(szString, *p);
if (p1 && p1 > p0)
p0 = p1;
}
return p0;
}
int elfexec(const char *path, int argc, char **argv)
{
int err, fd, len, errn;
const char *p;
unsigned fname;
__dpmi_paddr api;
__dpmi_shminfo shmi;
__dpmi_meminfo dm;
__dpmi_regs regs;
int en_dis = !(_crt0_startup_flags & _CRT0_FLAG_NEARPTR);
err = __dpmi_get_vendor_specific_api_entry_point("DJ64", &api);
if (err) {
fprintf(stderr, "DJ64 support missing\n");
return -1;
}
memset(®s, 0, sizeof(regs));
regs.d.ebx = 3; // get version
pltcall32(®s, api);
if (regs.d.eax < 2) {
fprintf(stderr, "unsupported DJ64 version %i\n", regs.d.eax);
return -1;
}
fd = open(path, O_RDONLY | O_BINARY);
if (fd == -1) {
fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
return -1;
}
len = filelength(fd);
p = strrpbrk(path, "/\\");
if (!p)
p = path;
fname = malloc32(strlen(p) + 1);
strcpy(DATA_PTR(fname), p);
shmi.size_requested = len;
shmi.name_offset = fname;
shmi.name_selector = _my_ds();
err = __dpmi_allocate_shared_memory(&shmi);
free32(fname);
if (err) {
close(fd);
fprintf(stderr, "Can't allocate shmem for %s\n", p);
return -1;
}
if (en_dis)
__djgpp_nearptr_enable();
err = read(fd, djaddr2ptr(shmi.address), len);
errn = errno;
if (en_dis)
__djgpp_nearptr_disable();
close(fd);
if (err == -1) {
fprintf(stderr, "error reading %s: %s\n", path, strerror(errn));
return -1;
}
if (err != len) {
fprintf(stderr, "read returned %i, need %i\n", err, len);
return -1;
}
dm.handle = shmi.handle;
dm.address = shmi.address;
dm.size = shmi.size;
err = __dpmi_free_physical_address_mapping(&dm);
assert(!err);
memset(®s, 0, sizeof(regs));
regs.d.ebx = 2; // exec
regs.x.di = shmi.handle & 0xffff;
regs.x.si = shmi.handle >> 16;
pltcall32(®s, api);
__dpmi_free_shared_memory(shmi.handle);
/* returning only 16bit AX allows to distinguish with -1 returns above */
return regs.x.ax;
}