Merge pull request #269 from davidgiven/dtrg-msdos386
Add a plat for 32-bit DOS executables.
This commit is contained in:
commit
0165c07c7b
3
README
3
README
|
@ -2,7 +2,7 @@
|
|||
===================================
|
||||
|
||||
© 1987-2005 Vrije Universiteit, Amsterdam
|
||||
2022-06-18
|
||||
2022-08-19
|
||||
|
||||
|
||||
INTRODUCTION
|
||||
|
@ -38,6 +38,7 @@ cpm produces i80 CP/M .COM files
|
|||
rpi produces Raspberry Pi GPU binaries
|
||||
pdpv7 produces PDP/11 V7 Unix binaries
|
||||
msdos86 produces i86 MS-DOS .COM files
|
||||
msdos386 produces i386 MS-DOS 32-bit DPMI .EXE files
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ vars.plats = {
|
|||
"linuxppc",
|
||||
"linuxmips",
|
||||
"msdos86",
|
||||
"msdos386",
|
||||
"osx386",
|
||||
"osxppc",
|
||||
"pc86",
|
||||
|
|
|
@ -184,10 +184,13 @@
|
|||
{0, NOOP_1, 0155, "ins"},
|
||||
{0, NOOP_1, 0252, "stosb"},
|
||||
{0, NOOP_1, 0253, "stos"},
|
||||
{0, NOOP_1, 0253, "stosw"},
|
||||
{0, NOOP_1, 0254, "lodsb"},
|
||||
{0, NOOP_1, 0255, "lods"},
|
||||
{0, NOOP_1, 0255, "lodsw"},
|
||||
{0, NOOP_1, 0256, "scasb"},
|
||||
{0, NOOP_1, 0257, "scas"},
|
||||
{0, NOOP_1, 0257, "scasw"},
|
||||
{0, NOOP_1, 0311, "leave"},
|
||||
{0, NOOP_1, 0316, "into"},
|
||||
{0, NOOP_1, 0317, "iret"},
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
void ea_1_16(int param)
|
||||
{
|
||||
reg_1 &= 0377;
|
||||
if ((reg_1 & 070) || (param & ~070)) {
|
||||
reg_1 &= 0377;
|
||||
if (param & ~070) {
|
||||
serror("bad operand");
|
||||
}
|
||||
emit1(reg_1 | param);
|
||||
|
@ -39,542 +39,545 @@ void ea_1_16(int param)
|
|||
}
|
||||
|
||||
void ea_1(int param) {
|
||||
if (! address_long) {
|
||||
ea_1_16(param);
|
||||
return;
|
||||
}
|
||||
if (is_expr(reg_1)) {
|
||||
serror("bad operand");
|
||||
return;
|
||||
}
|
||||
if (is_reg(reg_1)) {
|
||||
emit1(0300 | param | (reg_1&07));
|
||||
return;
|
||||
}
|
||||
if (rm_1 == 04) {
|
||||
/* sib field use here */
|
||||
emit1(mod_1 << 6 | param | 04);
|
||||
emit1(sib_1 | reg_1);
|
||||
}
|
||||
else emit1(mod_1<<6 | param | (reg_1&07));
|
||||
if ((mod_1 == 0 && reg_1 == 5) || mod_1 == 2) {
|
||||
/* ??? should this be protected by a call to "small" ??? */
|
||||
if (! address_long) {
|
||||
ea_1_16(param);
|
||||
return;
|
||||
}
|
||||
if (is_expr(reg_1)) {
|
||||
serror("bad operand");
|
||||
return;
|
||||
}
|
||||
if (is_reg(reg_1)) {
|
||||
emit1(0300 | param | (reg_1&07));
|
||||
return;
|
||||
}
|
||||
if (rm_1 == 04) {
|
||||
/* sib field use here */
|
||||
emit1(mod_1 << 6 | param | 04);
|
||||
emit1(sib_1 | reg_1);
|
||||
}
|
||||
else emit1(mod_1<<6 | param | (reg_1&07));
|
||||
if ((mod_1 == 0 && reg_1 == 5) || mod_1 == 2) {
|
||||
/* ??? should this be protected by a call to "small" ??? */
|
||||
#ifdef RELOCATION
|
||||
RELOMOVE(relonami, rel_1);
|
||||
newrelo(exp_1.typ, RELO4);
|
||||
RELOMOVE(relonami, rel_1);
|
||||
newrelo(exp_1.typ, RELO4);
|
||||
#endif
|
||||
emit4((long)(exp_1.val));
|
||||
}
|
||||
else if (mod_1 == 1) {
|
||||
emit1((int)(exp_1.val));
|
||||
}
|
||||
emit4((long)(exp_1.val));
|
||||
}
|
||||
else if (mod_1 == 1) {
|
||||
emit1((int)(exp_1.val));
|
||||
}
|
||||
}
|
||||
|
||||
void ea_2(int param) {
|
||||
|
||||
op_1 = op_2;
|
||||
RELOMOVE(rel_1, rel_2);
|
||||
ea_1(param);
|
||||
op_1 = op_2;
|
||||
RELOMOVE(rel_1, rel_2);
|
||||
ea_1(param);
|
||||
}
|
||||
|
||||
int checkscale(valu_t val)
|
||||
{
|
||||
int v = val;
|
||||
int v = val;
|
||||
|
||||
if (! address_long) {
|
||||
serror("scaling not allowed in 16-bit mode");
|
||||
return 0;
|
||||
}
|
||||
if (v != val) v = 0;
|
||||
switch(v) {
|
||||
case 1:
|
||||
return 0;
|
||||
case 2:
|
||||
return 1 << 6;
|
||||
case 4:
|
||||
return 2 << 6;
|
||||
case 8:
|
||||
return 3 << 6;
|
||||
default:
|
||||
serror("bad scale");
|
||||
return 0;
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
if (! address_long) {
|
||||
serror("scaling not allowed in 16-bit mode");
|
||||
return 0;
|
||||
}
|
||||
if (v != val) v = 0;
|
||||
switch(v) {
|
||||
case 1:
|
||||
return 0;
|
||||
case 2:
|
||||
return 1 << 6;
|
||||
case 4:
|
||||
return 2 << 6;
|
||||
case 8:
|
||||
return 3 << 6;
|
||||
default:
|
||||
serror("bad scale");
|
||||
return 0;
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
void reverse(void) {
|
||||
struct operand op;
|
||||
struct operand op;
|
||||
#ifdef RELOCATION
|
||||
int r = rel_1;
|
||||
int r = rel_1;
|
||||
|
||||
rel_1 = rel_2; rel_2 = r;
|
||||
rel_1 = rel_2; rel_2 = r;
|
||||
#endif
|
||||
op = op_1; op_1 = op_2; op_2 = op;
|
||||
op = op_1; op_1 = op_2; op_2 = op;
|
||||
}
|
||||
|
||||
void badsyntax(void)
|
||||
{
|
||||
|
||||
serror("bad operands");
|
||||
serror("bad operands");
|
||||
}
|
||||
|
||||
void regsize(int sz)
|
||||
{
|
||||
register int bit;
|
||||
register int bit;
|
||||
|
||||
bit = (sz&1) ? 0 : IS_R8;
|
||||
if ((is_reg(reg_1) && (reg_1 & IS_R8) != bit) ||
|
||||
(is_reg(reg_2) && (reg_2 & IS_R8) != bit))
|
||||
serror("register error");
|
||||
if (! address_long) {
|
||||
reg_1 &= ~010;
|
||||
reg_2 &= ~010;
|
||||
}
|
||||
bit = (sz&1) ? 0 : IS_R8;
|
||||
if ((is_reg(reg_1) && (reg_1 & IS_R8) != bit) ||
|
||||
(is_reg(reg_2) && (reg_2 & IS_R8) != bit))
|
||||
serror("register error");
|
||||
if (! address_long) {
|
||||
reg_1 &= ~010;
|
||||
reg_2 &= ~010;
|
||||
}
|
||||
}
|
||||
|
||||
void indexed(void) {
|
||||
if (address_long) {
|
||||
mod_2 = 0;
|
||||
if (sib_2 == -1)
|
||||
serror("register error");
|
||||
if (rm_2 == 0 && reg_2 == 4) {
|
||||
/* base register sp, no index register; use
|
||||
indexed mode without index register
|
||||
*/
|
||||
rm_2 = 04;
|
||||
sib_2 = 044;
|
||||
}
|
||||
if (reg_2 == 015) {
|
||||
reg_2 = 05;
|
||||
return;
|
||||
}
|
||||
if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 3)) {
|
||||
if (small(exp_2.val == 0 && reg_2 != 5, 1)) {
|
||||
}
|
||||
else mod_2 = 01;
|
||||
}
|
||||
else if (small(0, 1)) {
|
||||
}
|
||||
else mod_2 = 02;
|
||||
}
|
||||
else {
|
||||
if (reg_2 & ~7)
|
||||
serror("register error");
|
||||
if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 1)) {
|
||||
if (small(exp_2.val == 0 && reg_2 != 6, 1)) {
|
||||
}
|
||||
else reg_2 |= 0100;
|
||||
}
|
||||
else if (small(0, 1)) {
|
||||
}
|
||||
else reg_2 |= 0200;
|
||||
}
|
||||
if (address_long) {
|
||||
mod_2 = 0;
|
||||
if (sib_2 == -1)
|
||||
serror("register error");
|
||||
if (rm_2 == 0 && reg_2 == 4) {
|
||||
/* base register sp, no index register; use
|
||||
indexed mode without index register
|
||||
*/
|
||||
rm_2 = 04;
|
||||
sib_2 = 044;
|
||||
}
|
||||
if (reg_2 == 015) {
|
||||
reg_2 = 05;
|
||||
return;
|
||||
}
|
||||
if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 3)) {
|
||||
if (small(exp_2.val == 0 && reg_2 != 5, 1)) {
|
||||
}
|
||||
else mod_2 = 01;
|
||||
}
|
||||
else if (small(0, 1)) {
|
||||
}
|
||||
else mod_2 = 02;
|
||||
}
|
||||
else {
|
||||
if (reg_2 & ~7)
|
||||
serror("register error");
|
||||
if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 1)) {
|
||||
if (small(exp_2.val == 0 && reg_2 != 6, 1)) {
|
||||
}
|
||||
else reg_2 |= 0100;
|
||||
}
|
||||
else if (small(0, 1)) {
|
||||
}
|
||||
else reg_2 |= 0200;
|
||||
}
|
||||
}
|
||||
|
||||
void ebranch(register int opc,expr_t exp)
|
||||
{
|
||||
/* Conditional branching; Full displacements are available
|
||||
on the 80386, so the welknown trick with the reverse branch
|
||||
over a jump is not needed here.
|
||||
The only complication here is with the address size, which
|
||||
can be set with a prefix. In this case, the user gets what
|
||||
he asked for.
|
||||
*/
|
||||
register int sm;
|
||||
register long dist;
|
||||
int saving = address_long ? 4 : 2;
|
||||
/* Conditional branching; Full displacements are available
|
||||
on the 80386, so the welknown trick with the reverse branch
|
||||
over a jump is not needed here.
|
||||
The only complication here is with the address size, which
|
||||
can be set with a prefix. In this case, the user gets what
|
||||
he asked for.
|
||||
*/
|
||||
register int sm;
|
||||
register long dist;
|
||||
int saving = address_long ? 4 : 2;
|
||||
|
||||
if (opc == 0353) saving--;
|
||||
dist = exp.val - (DOTVAL + 2);
|
||||
if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
|
||||
dist -= DOTGAIN;
|
||||
sm = dist > 0 ? fitb(dist-saving) : fitb(dist);
|
||||
if ((exp.typ & ~S_DOT) != DOTTYP)
|
||||
sm = 0;
|
||||
if ((sm = small(sm,saving)) == 0) {
|
||||
if (opc == 0353) {
|
||||
emit1(0xe9);
|
||||
}
|
||||
else {
|
||||
emit1(0xF);
|
||||
emit1(opc | 0x80);
|
||||
}
|
||||
dist -= saving;
|
||||
exp.val = dist;
|
||||
adsize_exp(exp, RELPC);
|
||||
}
|
||||
else {
|
||||
if (opc == 0353) {
|
||||
emit1(opc);
|
||||
}
|
||||
else {
|
||||
emit1(opc | 0x70);
|
||||
}
|
||||
emit1((int)dist);
|
||||
}
|
||||
if (opc == 0353) saving--;
|
||||
dist = exp.val - (DOTVAL + 2);
|
||||
if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
|
||||
dist -= DOTGAIN;
|
||||
sm = dist > 0 ? fitb(dist-saving) : fitb(dist);
|
||||
if ((exp.typ & ~S_DOT) != DOTTYP)
|
||||
sm = 0;
|
||||
if ((sm = small(sm,saving)) == 0) {
|
||||
if (opc == 0353) {
|
||||
emit1(0xe9);
|
||||
}
|
||||
else {
|
||||
emit1(0xF);
|
||||
emit1(opc | 0x80);
|
||||
}
|
||||
dist -= saving;
|
||||
exp.val = dist;
|
||||
adsize_exp(exp, RELPC);
|
||||
}
|
||||
else {
|
||||
if (opc == 0353) {
|
||||
emit1(opc);
|
||||
}
|
||||
else {
|
||||
emit1(opc | 0x70);
|
||||
}
|
||||
emit1((int)dist);
|
||||
}
|
||||
}
|
||||
|
||||
void branch(register int opc,expr_t exp)
|
||||
{
|
||||
/* LOOP, JCXZ, etc. branch instructions.
|
||||
Here, the offset just must fit in a byte.
|
||||
*/
|
||||
register long dist;
|
||||
/* LOOP, JCXZ, etc. branch instructions.
|
||||
Here, the offset just must fit in a byte.
|
||||
*/
|
||||
register long dist;
|
||||
|
||||
dist = exp.val - (DOTVAL + 2);
|
||||
if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
|
||||
dist -= DOTGAIN;
|
||||
fit((exp.typ & ~S_DOT) == DOTTYP && fitb(dist));
|
||||
emit1(opc);
|
||||
emit1((int)dist);
|
||||
dist = exp.val - (DOTVAL + 2);
|
||||
if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
|
||||
dist -= DOTGAIN;
|
||||
fit((exp.typ & ~S_DOT) == DOTTYP && fitb(dist));
|
||||
emit1(opc);
|
||||
emit1((int)dist);
|
||||
}
|
||||
|
||||
void pushop(register int opc)
|
||||
{
|
||||
|
||||
regsize(1);
|
||||
if (is_segreg(reg_1)) {
|
||||
/* segment register */
|
||||
if ((reg_1 & 07) <= 3)
|
||||
emit1(6 | opc | (reg_1&7)<<3);
|
||||
else {
|
||||
emit1(0xF);
|
||||
emit1(0200 | opc | ((reg_1&7)<<3));
|
||||
}
|
||||
} else if (is_reg(reg_1)) {
|
||||
/* normal register */
|
||||
emit1(0120 | opc<<3 | (reg_1&7));
|
||||
} else if (opc == 0) {
|
||||
if (is_expr(reg_1)) {
|
||||
if (small(exp_1.typ == S_ABS && fitb(exp_1.val),
|
||||
operand_long ? 3 : 1)) {
|
||||
emit1(0152);
|
||||
emit1((int)(exp_1.val));
|
||||
}
|
||||
else {
|
||||
emit1(0150);
|
||||
RELOMOVE(relonami, rel_1);
|
||||
opsize_exp(exp_1, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
emit1(0377); ea_1(6<<3);
|
||||
}
|
||||
} else {
|
||||
emit1(0217); ea_1(0<<3);
|
||||
}
|
||||
regsize(1);
|
||||
if (is_segreg(reg_1)) {
|
||||
/* segment register */
|
||||
if ((reg_1 & 07) <= 3)
|
||||
emit1(6 | opc | (reg_1&7)<<3);
|
||||
else {
|
||||
emit1(0xF);
|
||||
emit1(0200 | opc | ((reg_1&7)<<3));
|
||||
}
|
||||
} else if (is_reg(reg_1)) {
|
||||
/* normal register */
|
||||
emit1(0120 | opc<<3 | (reg_1&7));
|
||||
} else if (opc == 0) {
|
||||
if (is_expr(reg_1)) {
|
||||
if (small(exp_1.typ == S_ABS && fitb(exp_1.val),
|
||||
operand_long ? 3 : 1)) {
|
||||
emit1(0152);
|
||||
emit1((int)(exp_1.val));
|
||||
}
|
||||
else {
|
||||
emit1(0150);
|
||||
RELOMOVE(relonami, rel_1);
|
||||
opsize_exp(exp_1, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
emit1(0377); ea_1(6<<3);
|
||||
}
|
||||
} else {
|
||||
emit1(0217); ea_1(0<<3);
|
||||
}
|
||||
}
|
||||
|
||||
void opsize_exp(expr_t exp, int nobyte)
|
||||
{
|
||||
if (! nobyte) {
|
||||
if (! nobyte) {
|
||||
#ifdef RELOCATION
|
||||
newrelo(exp.typ, RELO1);
|
||||
newrelo(exp.typ, RELO1);
|
||||
#endif
|
||||
emit1((int)(exp.val));
|
||||
}
|
||||
else if (operand_long) {
|
||||
emit1((int)(exp.val));
|
||||
}
|
||||
else if (operand_long) {
|
||||
#ifdef RELOCATION
|
||||
newrelo(exp.typ, RELO4);
|
||||
newrelo(exp.typ, RELO4);
|
||||
#endif
|
||||
emit4((long)(exp.val));
|
||||
}
|
||||
else {
|
||||
emit4((long)(exp.val));
|
||||
}
|
||||
else {
|
||||
#ifdef RELOCATION
|
||||
newrelo(exp.typ, RELO2);
|
||||
newrelo(exp.typ, RELO2);
|
||||
#endif
|
||||
emit2((int)(exp.val));
|
||||
}
|
||||
emit2((int)(exp.val));
|
||||
}
|
||||
}
|
||||
|
||||
void adsize_exp(expr_t exp, int relpc)
|
||||
{
|
||||
if (address_long) {
|
||||
if (address_long) {
|
||||
#ifdef RELOCATION
|
||||
newrelo(exp.typ, RELO4 | relpc);
|
||||
newrelo(exp.typ, RELO4 | relpc);
|
||||
#endif
|
||||
emit4((long)(exp.val));
|
||||
}
|
||||
else {
|
||||
emit4((long)(exp.val));
|
||||
}
|
||||
else {
|
||||
#ifdef RELOCATION
|
||||
newrelo(exp.typ, RELO2 | relpc);
|
||||
newrelo(exp.typ, RELO2 | relpc);
|
||||
#endif
|
||||
emit2((int)(exp.val));
|
||||
}
|
||||
emit2((int)(exp.val));
|
||||
}
|
||||
}
|
||||
|
||||
void addop(register int opc)
|
||||
{
|
||||
|
||||
regsize(opc);
|
||||
if (is_reg(reg_2)) {
|
||||
/* Add register to register or memory */
|
||||
emit1(opc); ea_1((reg_2&7)<<3);
|
||||
} else if (is_acc(reg_1) && is_expr(reg_2)) {
|
||||
/* Add immediate to accumulator */
|
||||
emit1(opc | 4);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
} else if (is_expr(reg_2)) {
|
||||
/* Add immediate to register or memory */
|
||||
if ((opc&1) == 0) {
|
||||
emit1(0200);
|
||||
} else if (! small(exp_2.typ == S_ABS && fitb(exp_2.val),
|
||||
operand_long ? 3 : 1)) {
|
||||
emit1(0201);
|
||||
} else {
|
||||
emit1(0203); opc &= ~1;
|
||||
}
|
||||
ea_1(opc & 070);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
} else if (is_reg(reg_1)) {
|
||||
/* Add register or memory to register */
|
||||
emit1(opc | 2);
|
||||
ea_2((reg_1&7)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
regsize(opc);
|
||||
if (is_reg(reg_2)) {
|
||||
/* Add register to register or memory */
|
||||
emit1(opc); ea_1((reg_2&7)<<3);
|
||||
} else if (is_acc(reg_1) && is_expr(reg_2)) {
|
||||
/* Add immediate to accumulator */
|
||||
emit1(opc | 4);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
} else if (is_expr(reg_2)) {
|
||||
/* Add immediate to register or memory */
|
||||
if ((opc&1) == 0) {
|
||||
emit1(0200);
|
||||
} else if (! small(exp_2.typ == S_ABS && fitb(exp_2.val),
|
||||
operand_long ? 3 : 1)) {
|
||||
emit1(0201);
|
||||
} else {
|
||||
emit1(0203); opc &= ~1;
|
||||
}
|
||||
ea_1(opc & 070);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
} else if (is_reg(reg_1)) {
|
||||
/* Add register or memory to register */
|
||||
emit1(opc | 2);
|
||||
ea_2((reg_1&7)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
}
|
||||
|
||||
void rolop(register int opc)
|
||||
{
|
||||
register int oreg;
|
||||
register int oreg;
|
||||
|
||||
oreg = reg_2;
|
||||
reg_2 = reg_1;
|
||||
regsize(opc);
|
||||
if (oreg == (IS_R8 | 1 | (address_long ? 0 : 0300))) {
|
||||
/* cl register */
|
||||
emit1(0322 | (opc&1)); ea_1(opc&070);
|
||||
} else if (is_expr(oreg)) {
|
||||
if (small(exp_2.typ == S_ABS && exp_2.val == 1, 1)) {
|
||||
/* shift by 1 */
|
||||
emit1(0320 | (opc&1)); ea_1(opc&070);
|
||||
} else {
|
||||
/* shift by byte count */
|
||||
emit1(0300 | (opc & 1));
|
||||
ea_1(opc & 070);
|
||||
oreg = reg_2;
|
||||
reg_2 = reg_1;
|
||||
regsize(opc);
|
||||
if (oreg == (IS_R8 | 1 | (address_long ? 0 : 0300))) {
|
||||
/* cl register */
|
||||
emit1(0322 | (opc&1)); ea_1(opc&070);
|
||||
} else if (is_expr(oreg)) {
|
||||
if (small(exp_2.typ == S_ABS && exp_2.val == 1, 1)) {
|
||||
/* shift by 1 */
|
||||
emit1(0320 | (opc&1)); ea_1(opc&070);
|
||||
} else {
|
||||
/* shift by byte count */
|
||||
emit1(0300 | (opc & 1));
|
||||
ea_1(opc & 070);
|
||||
#ifdef RELOCATION
|
||||
RELOMOVE(relonami, rel_2);
|
||||
newrelo(exp_2.typ, RELO1);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
newrelo(exp_2.typ, RELO1);
|
||||
#endif
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
}
|
||||
else
|
||||
badsyntax();
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
}
|
||||
else
|
||||
badsyntax();
|
||||
}
|
||||
|
||||
void incop(register int opc)
|
||||
{
|
||||
|
||||
regsize(opc);
|
||||
if ((opc&1) && is_reg(reg_1)) {
|
||||
/* word register */
|
||||
emit1(0100 | (opc&010) | (reg_1&7));
|
||||
} else {
|
||||
emit1(0376 | (opc&1));
|
||||
ea_1(opc & 010);
|
||||
}
|
||||
regsize(opc);
|
||||
if ((opc&1) && is_reg(reg_1)) {
|
||||
/* word register */
|
||||
emit1(0100 | (opc&010) | (reg_1&7));
|
||||
} else {
|
||||
emit1(0376 | (opc&1));
|
||||
ea_1(opc & 010);
|
||||
}
|
||||
}
|
||||
|
||||
void callop(register int opc)
|
||||
{
|
||||
|
||||
regsize(1);
|
||||
if (is_expr(reg_1)) {
|
||||
if (opc == (040+(0351<<8))) {
|
||||
RELOMOVE(relonami, rel_1);
|
||||
ebranch(0353,exp_1);
|
||||
} else {
|
||||
exp_1.val -= (DOTVAL+3 + (address_long ? 2 : 0));
|
||||
emit1(opc>>8);
|
||||
RELOMOVE(relonami, rel_1);
|
||||
adsize_exp(exp_1, RELPC);
|
||||
}
|
||||
} else {
|
||||
emit1(0377); ea_1(opc&070);
|
||||
}
|
||||
regsize(1);
|
||||
if (is_expr(reg_1)) {
|
||||
if (opc == (040+(0351<<8))) {
|
||||
RELOMOVE(relonami, rel_1);
|
||||
ebranch(0353,exp_1);
|
||||
} else {
|
||||
exp_1.val -= (DOTVAL+3 + (address_long ? 2 : 0));
|
||||
emit1(opc>>8);
|
||||
RELOMOVE(relonami, rel_1);
|
||||
adsize_exp(exp_1, RELPC);
|
||||
}
|
||||
} else {
|
||||
emit1(0377); ea_1(opc&070);
|
||||
}
|
||||
}
|
||||
|
||||
void xchg(register int opc)
|
||||
{
|
||||
|
||||
regsize(opc);
|
||||
if (! is_reg(reg_1) || is_acc(reg_2)) {
|
||||
reverse();
|
||||
}
|
||||
if (opc == 1 && is_acc(reg_1) && is_reg(reg_2)) {
|
||||
emit1(0220 | (reg_2&7));
|
||||
} else if (is_reg(reg_1)) {
|
||||
emit1(0206 | opc); ea_2((reg_1&7)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
regsize(opc);
|
||||
if (! is_reg(reg_1) || is_acc(reg_2)) {
|
||||
reverse();
|
||||
}
|
||||
if (opc == 1 && is_acc(reg_1) && is_reg(reg_2)) {
|
||||
emit1(0220 | (reg_2&7));
|
||||
} else if (is_reg(reg_1)) {
|
||||
emit1(0206 | opc); ea_2((reg_1&7)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
}
|
||||
|
||||
void test(register int opc)
|
||||
{
|
||||
|
||||
regsize(opc);
|
||||
if (is_reg(reg_2) || is_expr(reg_1))
|
||||
reverse();
|
||||
if (is_expr(reg_2)) {
|
||||
if (is_acc(reg_1)) {
|
||||
emit1(0250 | opc);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
}
|
||||
else {
|
||||
emit1(0366 | opc);
|
||||
ea_1(0<<3);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
}
|
||||
} else if (is_reg(reg_1)) {
|
||||
emit1(0204 | opc); ea_2((reg_1&7)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
regsize(opc);
|
||||
if (is_reg(reg_2) || is_expr(reg_1))
|
||||
reverse();
|
||||
if (is_expr(reg_2)) {
|
||||
if (is_acc(reg_1)) {
|
||||
emit1(0250 | opc);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
}
|
||||
else {
|
||||
emit1(0366 | opc);
|
||||
ea_1(0<<3);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
}
|
||||
} else if (is_reg(reg_1)) {
|
||||
emit1(0204 | opc); ea_2((reg_1&7)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
}
|
||||
|
||||
void mov(register int opc)
|
||||
{
|
||||
|
||||
regsize(opc);
|
||||
if (is_segreg(reg_1)) {
|
||||
/* to segment register */
|
||||
emit1(0216); ea_2((reg_1&07)<<3);
|
||||
} else if (is_segreg(reg_2)) {
|
||||
/* from segment register */
|
||||
emit1(0214); ea_1((reg_2&07)<<3);
|
||||
} else if (is_expr(reg_2)) {
|
||||
/* from immediate */
|
||||
if (is_reg(reg_1)) {
|
||||
/* to register */
|
||||
emit1(0260 | opc<<3 | (reg_1&7));
|
||||
} else {
|
||||
/* to memory */
|
||||
emit1(0306 | opc); ea_1(0<<3);
|
||||
}
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
} else if (rm_1 == 05 && is_acc(reg_2)) {
|
||||
/* from accumulator to memory (displacement) */
|
||||
emit1(0242 | opc);
|
||||
RELOMOVE(relonami, rel_1);
|
||||
adsize_exp(exp_1, 0);
|
||||
} else if (rm_2 == 05 && is_acc(reg_1)) {
|
||||
/* from memory (displacement) to accumulator */
|
||||
emit1(0240 | opc);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
adsize_exp(exp_2, 0);
|
||||
} else if (is_reg(reg_2)) {
|
||||
/* from register to memory or register */
|
||||
emit1(0210 | opc); ea_1((reg_2&07)<<3);
|
||||
} else if (is_reg(reg_1)) {
|
||||
/* from memory or register to register */
|
||||
emit1(0212 | opc); ea_2((reg_1&07)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
regsize(opc);
|
||||
if (is_segreg(reg_1)) {
|
||||
/* to segment register */
|
||||
emit1(0216); ea_2((reg_1&07)<<3);
|
||||
} else if (is_segreg(reg_2)) {
|
||||
/* from segment register */
|
||||
emit1(0214); ea_1((reg_2&07)<<3);
|
||||
} else if (is_expr(reg_2)) {
|
||||
/* from immediate */
|
||||
if (is_reg(reg_1)) {
|
||||
/* to register */
|
||||
emit1(0260 | opc<<3 | (reg_1&7));
|
||||
} else {
|
||||
/* to memory */
|
||||
emit1(0306 | opc); ea_1(0<<3);
|
||||
}
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
} else if (rm_1 == 05 && is_acc(reg_2)) {
|
||||
/* from accumulator to memory (displacement) */
|
||||
emit1(0242 | opc);
|
||||
RELOMOVE(relonami, rel_1);
|
||||
adsize_exp(exp_1, 0);
|
||||
} else if (rm_2 == 05 && is_acc(reg_1)) {
|
||||
/* from memory (displacement) to accumulator */
|
||||
emit1(0240 | opc);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
adsize_exp(exp_2, 0);
|
||||
} else if (is_reg(reg_2)) {
|
||||
/* from register to memory or register */
|
||||
emit1(0210 | opc); ea_1((reg_2&07)<<3);
|
||||
} else if (is_reg(reg_1)) {
|
||||
/* from memory or register to register */
|
||||
emit1(0212 | opc); ea_2((reg_1&07)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
}
|
||||
|
||||
void extshft(int opc, int reg)
|
||||
{
|
||||
int oreg2 = reg_2;
|
||||
int oreg2 = reg_2;
|
||||
|
||||
reg_2 = reg_1;
|
||||
regsize(1);
|
||||
reg_2 = reg_1;
|
||||
regsize(1);
|
||||
|
||||
emit1(0xF);
|
||||
if (oreg2 == (IS_R8 | 1 | (address_long ? 0 : 0300))) {
|
||||
/* cl register */
|
||||
emit1(opc|1);
|
||||
ea_1(reg << 3);
|
||||
}
|
||||
else if (is_expr(oreg2)) {
|
||||
emit1(opc);
|
||||
ea_1(reg << 3);
|
||||
emit1(0xF);
|
||||
if (oreg2 == (IS_R8 | 1 | (address_long ? 0 : 0300))) {
|
||||
/* cl register */
|
||||
emit1(opc|1);
|
||||
ea_1(reg << 3);
|
||||
}
|
||||
else if (is_expr(oreg2)) {
|
||||
emit1(opc);
|
||||
ea_1(reg << 3);
|
||||
#ifdef RELOCATION
|
||||
RELOMOVE(relonami, rel_2);
|
||||
newrelo(exp_2.typ, RELO1);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
newrelo(exp_2.typ, RELO1);
|
||||
#endif
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
else badsyntax();
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
else badsyntax();
|
||||
}
|
||||
|
||||
void bittestop(int opc)
|
||||
{
|
||||
regsize(1);
|
||||
emit1(0xF);
|
||||
if (is_expr(reg_2)) {
|
||||
emit1(0272);
|
||||
ea_1(opc << 3);
|
||||
regsize(1);
|
||||
emit1(0xF);
|
||||
if (is_expr(reg_2)) {
|
||||
emit1(0272);
|
||||
ea_1(opc << 3);
|
||||
#ifdef RELOCATION
|
||||
RELOMOVE(relonami, rel_2);
|
||||
newrelo(exp_2.typ, RELO1);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
newrelo(exp_2.typ, RELO1);
|
||||
#endif
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
else if (is_reg(reg_2)) {
|
||||
emit1(0203 | (opc<<3));
|
||||
ea_1((reg_2&7)<<3);
|
||||
}
|
||||
else badsyntax();
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
else if (is_reg(reg_2)) {
|
||||
emit1(0203 | (opc<<3));
|
||||
ea_1((reg_2&7)<<3);
|
||||
}
|
||||
else badsyntax();
|
||||
}
|
||||
|
||||
void imul(int reg)
|
||||
{
|
||||
/* This instruction is more elaborate on the 80386. Its most
|
||||
general form is:
|
||||
imul reg, reg_or_mem, immediate.
|
||||
This is the form processed here.
|
||||
*/
|
||||
regsize(1);
|
||||
if (is_expr(reg_1)) {
|
||||
/* To also handle
|
||||
imul reg, immediate, reg_or_mem
|
||||
*/
|
||||
reverse();
|
||||
}
|
||||
if (is_expr(reg_2)) {
|
||||
/* The immediate form; two cases: */
|
||||
if (small(exp_2.typ == S_ABS && fitb(exp_2.val),
|
||||
operand_long ? 3 : 1)) {
|
||||
/* case 1: 1 byte encoding of immediate */
|
||||
emit1(0153);
|
||||
ea_1((reg & 07) << 3);
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
else {
|
||||
/* case 2: WORD or DWORD encoding of immediate */
|
||||
emit1(0151);
|
||||
ea_1((reg & 07) << 3);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, 1);
|
||||
}
|
||||
}
|
||||
else if (is_reg(reg_1) && ((reg_1&7) == (reg & 07))) {
|
||||
/* the "reg" field and the "reg_or_mem" field are the same,
|
||||
and the 3rd operand is not an immediate ...
|
||||
*/
|
||||
if (reg == 0) {
|
||||
/* how lucky we are, the target is the ax register */
|
||||
/* However, we cannot make an optimization for f.i.
|
||||
imul eax, blablabla
|
||||
because the latter does not affect edx, whereas
|
||||
imul blablabla
|
||||
does! Therefore, "reg" is or-ed with 0x10 in the
|
||||
former case, so that the test above fails.
|
||||
*/
|
||||
emit1(0367);
|
||||
ea_2(050);
|
||||
}
|
||||
else {
|
||||
/* another register ... */
|
||||
emit1(0xF);
|
||||
emit1(0257);
|
||||
ea_2((reg & 07) << 3);
|
||||
}
|
||||
}
|
||||
else badsyntax();
|
||||
/* This instruction is more elaborate on the 80386. Its most
|
||||
general form is:
|
||||
imul reg, reg_or_mem, immediate.
|
||||
This is the form processed here.
|
||||
*/
|
||||
regsize(1);
|
||||
if (is_expr(reg_1)) {
|
||||
/* To also handle
|
||||
imul reg, immediate, reg_or_mem
|
||||
*/
|
||||
reverse();
|
||||
}
|
||||
if (is_expr(reg_2)) {
|
||||
/* The immediate form; two cases: */
|
||||
if (small(exp_2.typ == S_ABS && fitb(exp_2.val),
|
||||
operand_long ? 3 : 1)) {
|
||||
/* case 1: 1 byte encoding of immediate */
|
||||
emit1(0153);
|
||||
ea_1((reg & 07) << 3);
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
else {
|
||||
/* case 2: WORD or DWORD encoding of immediate */
|
||||
emit1(0151);
|
||||
ea_1((reg & 07) << 3);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, 1);
|
||||
}
|
||||
}
|
||||
else if (is_reg(reg_1) && ((reg_1&7) == (reg & 07))) {
|
||||
/* the "reg" field and the "reg_or_mem" field are the same,
|
||||
and the 3rd operand is not an immediate ...
|
||||
*/
|
||||
if (reg == 0) {
|
||||
/* how lucky we are, the target is the ax register */
|
||||
/* However, we cannot make an optimization for f.i.
|
||||
imul eax, blablabla
|
||||
because the latter does not affect edx, whereas
|
||||
imul blablabla
|
||||
does! Therefore, "reg" is or-ed with 0x10 in the
|
||||
former case, so that the test above fails.
|
||||
*/
|
||||
emit1(0367);
|
||||
ea_2(050);
|
||||
}
|
||||
else {
|
||||
/* another register ... */
|
||||
emit1(0xF);
|
||||
emit1(0257);
|
||||
ea_2((reg & 07) << 3);
|
||||
}
|
||||
}
|
||||
else badsyntax();
|
||||
}
|
||||
|
||||
// vim: ts=8 sw=8 et
|
||||
|
||||
|
|
|
@ -86,6 +86,9 @@ char* remember(char* s)
|
|||
|
||||
int combine(int typ1, int typ2, int op)
|
||||
{
|
||||
typ1 &= ~S_VAR;
|
||||
typ2 &= ~S_VAR;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
|
|
11
plat/msdos/include/ack/plat.h
Normal file
11
plat/msdos/include/ack/plat.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#ifndef _ACK_PLAT_H
|
||||
#define _ACK_PLAT_H
|
||||
|
||||
#define ACKCONF_WANT_O_TEXT_O_BINARY 1
|
||||
|
||||
#endif
|
24
plat/msdos/include/build.lua
Normal file
24
plat/msdos/include/build.lua
Normal file
|
@ -0,0 +1,24 @@
|
|||
include("plat/build.lua")
|
||||
|
||||
headermap = {}
|
||||
packagemap = {}
|
||||
|
||||
local function addheader(h)
|
||||
headermap[h] = "./"..h
|
||||
packagemap["$(PLATIND)/msdos86/include/"..h] = "./"..h
|
||||
end
|
||||
|
||||
addheader("ack/plat.h")
|
||||
addheader("sys/types.h")
|
||||
|
||||
acklibrary {
|
||||
name = "headers",
|
||||
hdrs = headermap
|
||||
}
|
||||
|
||||
installable {
|
||||
name = "pkg",
|
||||
map = packagemap
|
||||
}
|
||||
|
||||
|
9
plat/msdos/include/sys/types.h
Normal file
9
plat/msdos/include/sys/types.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef _SYS_TYPES_H
|
||||
#define _SYS_TYPES_H
|
||||
|
||||
typedef long pid_t;
|
||||
typedef int mode_t;
|
||||
typedef long time_t;
|
||||
typedef long suseconds_t;
|
||||
|
||||
#endif
|
28
plat/msdos/libsys/build.lua
Normal file
28
plat/msdos/libsys/build.lua
Normal file
|
@ -0,0 +1,28 @@
|
|||
bundle {
|
||||
name = "srcs",
|
||||
srcs = {
|
||||
"./creat.c",
|
||||
"./gettimeofday.c",
|
||||
"./kill.c",
|
||||
"./lseek.c",
|
||||
"./open.c",
|
||||
"./read.c",
|
||||
"./setmode.c",
|
||||
"./signal.c",
|
||||
"./sys_fdmodes.c",
|
||||
"./sys_getmode.c",
|
||||
"./sys_initmain.c",
|
||||
"./sys_iseof.c",
|
||||
"./sys_seteof.c",
|
||||
"./sys_seterrno.c",
|
||||
"./sys_setmode.c",
|
||||
"./write.c",
|
||||
}
|
||||
}
|
||||
|
||||
bundle {
|
||||
name = "headers",
|
||||
srcs = {
|
||||
"./libsys.h"
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
@ -16,9 +17,7 @@ ssize_t read(int fd, void* buffer, size_t count)
|
|||
ssize_t r, tot;
|
||||
size_t left;
|
||||
int eof = 0;
|
||||
|
||||
if (!count || _sys_getmode(fd) == O_BINARY)
|
||||
return _sys_rawread(fd, buffer, count);
|
||||
bool text = _sys_getmode(fd) == O_TEXT;
|
||||
|
||||
if (_sys_iseof(fd))
|
||||
return 0;
|
||||
|
@ -47,33 +46,36 @@ ssize_t read(int fd, void* buffer, size_t count)
|
|||
if (r <= 0)
|
||||
return tot ? tot : r;
|
||||
|
||||
q = memchr(p, 0x1a, (size_t)r);
|
||||
if (q)
|
||||
if (text)
|
||||
{
|
||||
_sys_rawlseek(fd, (off_t)(q - p) - r, SEEK_CUR);
|
||||
r = q - p;
|
||||
eof = 1;
|
||||
_sys_seteof(fd, 1);
|
||||
}
|
||||
|
||||
q = memchr(p, '\r', (size_t)r);
|
||||
if (!q)
|
||||
return tot + r;
|
||||
|
||||
tot += q - p;
|
||||
left = r - (q + 1 - p);
|
||||
p = q;
|
||||
++q;
|
||||
|
||||
while (left)
|
||||
{
|
||||
char c = *q++;
|
||||
if (c != '\r')
|
||||
q = memchr(p, 0x1a, (size_t)r);
|
||||
if (q)
|
||||
{
|
||||
*p++ = c;
|
||||
++tot;
|
||||
_sys_rawlseek(fd, (off_t)(q - p) - r, SEEK_CUR);
|
||||
r = q - p;
|
||||
eof = 1;
|
||||
_sys_seteof(fd, 1);
|
||||
}
|
||||
|
||||
q = memchr(p, '\r', (size_t)r);
|
||||
if (!q)
|
||||
return tot + r;
|
||||
|
||||
tot += q - p;
|
||||
left = r - (q + 1 - p);
|
||||
p = q;
|
||||
++q;
|
||||
|
||||
while (left)
|
||||
{
|
||||
char c = *q++;
|
||||
if (c != '\r')
|
||||
{
|
||||
*p++ = c;
|
||||
++tot;
|
||||
}
|
||||
--left;
|
||||
}
|
||||
--left;
|
||||
}
|
||||
} while (tot < count && !eof && _sys_isreadyr(fd));
|
||||
|
74
plat/msdos/libsys/write.c
Normal file
74
plat/msdos/libsys/write.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include "libsys.h"
|
||||
|
||||
ssize_t write(int fd, void* buffer, size_t count)
|
||||
{
|
||||
static const char crlf[2] = "\r\n";
|
||||
int i;
|
||||
char *p, *q;
|
||||
size_t left, n;
|
||||
ssize_t r, tot;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
p = buffer;
|
||||
left = count;
|
||||
tot = 0;
|
||||
|
||||
if (_sys_getmode(fd) == O_BINARY)
|
||||
{
|
||||
while (left)
|
||||
{
|
||||
r = _sys_rawwrite(fd, p, left);
|
||||
if (r <= 0)
|
||||
return tot ? tot : r;
|
||||
tot += r;
|
||||
p += r;
|
||||
left -= r;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the file descriptor is an O_TEXT fd, translate LFs to CRLFs. */
|
||||
while (left)
|
||||
{
|
||||
q = memchr(p, '\n', left);
|
||||
if (!q)
|
||||
return _sys_rawwrite(fd, p, left);
|
||||
|
||||
n = q - p;
|
||||
if (n)
|
||||
{
|
||||
r = _sys_rawwrite(fd, p, n);
|
||||
if (r <= 0)
|
||||
return tot ? tot : r;
|
||||
tot += r;
|
||||
p += r;
|
||||
left -= r;
|
||||
if (r != n)
|
||||
break;
|
||||
}
|
||||
|
||||
r = _sys_rawwrite(fd, crlf, sizeof crlf);
|
||||
if (r != 2)
|
||||
{
|
||||
if (r > 0)
|
||||
r = 0;
|
||||
return tot ? tot : r;
|
||||
}
|
||||
++tot;
|
||||
++p;
|
||||
--left;
|
||||
}
|
||||
}
|
||||
return tot;
|
||||
}
|
24
plat/msdos386/README
Normal file
24
plat/msdos386/README
Normal file
|
@ -0,0 +1,24 @@
|
|||
The msdos386 platform
|
||||
=====================
|
||||
|
||||
msdos386 is an i386-based BSP that produces DPMI DOS executables. It should
|
||||
have the same functionality as msdos86 (as the libc is all the same code), but
|
||||
has been much less well tested.
|
||||
|
||||
The code runs in flat 32-bit mode, so normal 32-bit pointers work with no
|
||||
worries about segmentation. It requires a DPMI host to run; it was tested with
|
||||
CWSDPMI. It will _not_ automatically load the host --- you need to manually
|
||||
install the DPMI hsot first.
|
||||
|
||||
IEEE floating point is available, but requires an FPU.
|
||||
|
||||
|
||||
Example command line
|
||||
====================
|
||||
|
||||
ack -mmsdos386 -O -o msdos386.exe examples/paranoia.c
|
||||
|
||||
|
||||
David Given
|
||||
dg@cowlark.com
|
||||
|
236
plat/msdos386/boot.s
Normal file
236
plat/msdos386/boot.s
Normal file
|
@ -0,0 +1,236 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
#define STACK_BUFFER 128 /* number of bytes to leave for stack */
|
||||
|
||||
! g 18b to break at the retf before coming here
|
||||
begtext:
|
||||
! On entry, the stub has cs and ds pointing at the 32-bit
|
||||
! segment, but ss is still pointing at the 16-bit segment.
|
||||
!
|
||||
! ax: pmode code segment of stub
|
||||
! bx: pmode data segment of stub
|
||||
! cx: rmode segment of stub
|
||||
! dx: pointer to realloc routine (in stub)e
|
||||
! si: pointer to interrupt routine (in stub)
|
||||
! di: pointer to transfer buffer (in stub)
|
||||
|
||||
! Resize the segment to include the BSS.
|
||||
|
||||
o16 cseg mov (realloc_ptr+4), ax
|
||||
cseg mov (realloc_ptr+0), edx
|
||||
cseg o16 mov (pmode_cs), ax
|
||||
cseg o16 mov (pmode_ds), bx
|
||||
cseg o16 mov (rmode), cx
|
||||
cseg o16 mov (interrupt_ptr+4), ax
|
||||
cseg mov (interrupt_ptr+0), esi
|
||||
cseg o16 mov (transfer_buffer_ptr), di
|
||||
|
||||
mov eax, __end
|
||||
cseg callf (realloc_ptr)
|
||||
|
||||
! Clear BSS.
|
||||
|
||||
mov edi, begbss
|
||||
mov ecx, endbss+1
|
||||
sub ecx, edi
|
||||
shr ecx, 1
|
||||
xor eax, eax
|
||||
cld
|
||||
rep stosw
|
||||
|
||||
! It's now safe to switch stacks.
|
||||
|
||||
cli
|
||||
mov eax, ds
|
||||
mov ss, eax
|
||||
mov sp, .stack
|
||||
sti
|
||||
|
||||
! Create a handle for low 1MB access.
|
||||
|
||||
o16 mov ax, 0x0000
|
||||
o16 mov cx, 1
|
||||
int 0x31 ! allocate LDT
|
||||
mov es, ax
|
||||
o16 mov bx, ax
|
||||
o16 mov (.doshandle), bx
|
||||
mov es, bx
|
||||
|
||||
xor ecx, ecx
|
||||
xor edx, edx
|
||||
o16 mov ax, 0x0007
|
||||
int 0x31 ! set base address to 0
|
||||
o16 mov cx, 0x0010
|
||||
o16 mov ax, 0x0008
|
||||
int 0x31 ! set limit to 1MB
|
||||
|
||||
mov cx, ds
|
||||
and cx, 3
|
||||
shl cx, 5
|
||||
or cx, 0xc093 ! 32-bit, big, data, r/w, expand-up
|
||||
mov ax, 0x0009
|
||||
int 0x31 ! set descriptor access rights
|
||||
|
||||
! Locate the PSP.
|
||||
|
||||
movb ah, 0x62
|
||||
int 0x21
|
||||
movzx esi, bx
|
||||
shl esi, 4 ! convert to linear address
|
||||
|
||||
! Copy the whole thing into 32-bit memory.
|
||||
|
||||
mov ecx, 0x100/4
|
||||
mov edi, _psp
|
||||
cld
|
||||
1:
|
||||
eseg lods
|
||||
mov (edi), eax
|
||||
add edi, 4
|
||||
loop 1b
|
||||
|
||||
! Find the environment.
|
||||
|
||||
mov es, (_psp + 0x002C) ! converted to pmode segment
|
||||
|
||||
! Count the size of the environment variable block.
|
||||
|
||||
xorb al, al ! byte to test for
|
||||
xor edi, edi
|
||||
xor edx, edx
|
||||
cld
|
||||
mov ecx, -1
|
||||
scasb
|
||||
jz 2f ! empty environment
|
||||
1:
|
||||
repnz scasb
|
||||
inc edx
|
||||
scasb
|
||||
jnz 1b
|
||||
2:
|
||||
add edi, 2 ! skip the mysterious word
|
||||
repnz scasb ! program name
|
||||
|
||||
! Copy the whole environment block onto the stack.
|
||||
|
||||
mov esi, edi
|
||||
add esi, 3
|
||||
and esi, ~3 ! round up
|
||||
jz empty_environment
|
||||
mov ecx, esi
|
||||
shr ecx, 2 ! number of dwords
|
||||
std
|
||||
sub esi, 4
|
||||
1:
|
||||
eseg lods
|
||||
push eax
|
||||
loop 1b
|
||||
empty_environment:
|
||||
mov ecx, esp ! environment data
|
||||
|
||||
! Reset DF and es properly.
|
||||
|
||||
cld
|
||||
push ss
|
||||
pop es
|
||||
|
||||
! Reserve space for argc and the argv and envp pointers on the
|
||||
! stack. These will be passed to __m_a_i_n later.
|
||||
|
||||
sub esp, 3*4
|
||||
mov eax, esp
|
||||
|
||||
! Build up argc, argv[], and envp[].
|
||||
push eax ! output buffer for argc, argv, envp
|
||||
push 3 ! MS-DOS version
|
||||
push ecx ! env. string data
|
||||
push edx ! count of env. vars.
|
||||
push _psp+0x80 ! raw command line
|
||||
call __sys_initmain
|
||||
add esp, 5*4
|
||||
|
||||
! Bail out if something went wrong.
|
||||
test eax, eax
|
||||
jnz no_room
|
||||
|
||||
! argc, argv, and envp are now at the stack top. Now go.
|
||||
call __m_a_i_n
|
||||
add sp, 3*4
|
||||
push ax
|
||||
call _exit
|
||||
|
||||
no_room:
|
||||
mov dx, no_room_msg
|
||||
!call dos_msg
|
||||
movb al, -1
|
||||
jmp al_exit
|
||||
|
||||
! Exit.
|
||||
.define __exit
|
||||
.extern __exit
|
||||
.define EXIT
|
||||
.extern EXIT
|
||||
__exit:
|
||||
EXIT:
|
||||
pop bx
|
||||
pop ax
|
||||
al_exit:
|
||||
movb ah, 0x4c
|
||||
int 0x21
|
||||
|
||||
! These must be in the code segment due to bootstrap issues.
|
||||
realloc_ptr: .space 6 ! far
|
||||
interrupt_ptr: .space 6 ! far
|
||||
transfer_buffer_ptr: .space 2 ! near
|
||||
rmode: .space 2
|
||||
pmode_cs: .space 2
|
||||
pmode_ds: .space 2
|
||||
|
||||
.define realloc_ptr
|
||||
.define interrupt_ptr
|
||||
.define rmode
|
||||
.define pmode_cs
|
||||
.define pmode_ds
|
||||
.define transfer_buffer_ptr
|
||||
|
||||
! Define symbols at the beginning of our various segments, so that we can find
|
||||
! them. (Except .text, which has already been done.)
|
||||
|
||||
.define begtext, begdata, begbss
|
||||
.sect .data; begdata:
|
||||
.sect .rom; begrom:
|
||||
.sect .bss; begbss:
|
||||
|
||||
.sect .rom
|
||||
|
||||
! Some text messages.
|
||||
bad_sys_msg: .ascii 'Bad DOS$'
|
||||
no_room_msg: .ascii 'No room$'
|
||||
|
||||
! Some magic data. All EM systems need these.
|
||||
|
||||
.define .trppc, .ignmask, _errno
|
||||
.comm .trppc, 4
|
||||
.comm .ignmask, 4
|
||||
.comm _errno, 4
|
||||
|
||||
.comm .doshandle, 2
|
||||
.comm _psp, 256
|
||||
|
||||
.sect .bss
|
||||
.space 32*1024
|
||||
.stack:
|
||||
|
||||
! vim: ts=4 sw=4 et ft=asm
|
||||
|
52
plat/msdos386/build-pkg.lua
Normal file
52
plat/msdos386/build-pkg.lua
Normal file
|
@ -0,0 +1,52 @@
|
|||
include("plat/build.lua")
|
||||
|
||||
ackfile {
|
||||
name = "boot",
|
||||
srcs = { "./boot.s" },
|
||||
vars = { plat = "msdos386" }
|
||||
}
|
||||
|
||||
ackfile {
|
||||
name = "stub",
|
||||
srcs = { "./stub.s" },
|
||||
vars = { plat = "msdos386" }
|
||||
}
|
||||
|
||||
normalrule {
|
||||
name = "stub_aout",
|
||||
ins = {
|
||||
"util/led+led",
|
||||
"+stub"
|
||||
},
|
||||
outleaves = { "stub.aout" },
|
||||
commands = { "%{ins[1]} %{ins[2]} -o %{outs[1]}" }
|
||||
}
|
||||
|
||||
normalrule {
|
||||
name = "stub_exe",
|
||||
ins = {
|
||||
"util/amisc+aslod",
|
||||
"+stub_aout"
|
||||
},
|
||||
outleaves = { "stub.exe" },
|
||||
commands = { "%{ins[1]} %{ins[2]} %{outs[1]}" }
|
||||
}
|
||||
|
||||
build_plat_libs {
|
||||
name = "libs",
|
||||
arch = "i386",
|
||||
plat = "msdos386",
|
||||
}
|
||||
|
||||
installable {
|
||||
name = "pkg",
|
||||
map = {
|
||||
"+tools",
|
||||
"+libs",
|
||||
"./include+pkg",
|
||||
["$(PLATIND)/msdos386/boot.o"] = "+boot",
|
||||
["$(PLATIND)/msdos386/stub.exe"] = "+stub_exe",
|
||||
["$(PLATIND)/msdos386/libsys.a"] = "./libsys+lib",
|
||||
}
|
||||
}
|
||||
|
21
plat/msdos386/build-tools.lua
Normal file
21
plat/msdos386/build-tools.lua
Normal file
|
@ -0,0 +1,21 @@
|
|||
include("plat/build.lua")
|
||||
|
||||
build_as {
|
||||
name = "as",
|
||||
arch = "i386",
|
||||
}
|
||||
|
||||
build_ncg {
|
||||
name = "ncg",
|
||||
arch = "i386",
|
||||
}
|
||||
|
||||
return installable {
|
||||
name = "tools",
|
||||
map = {
|
||||
["$(PLATDEP)/msdos386/as"] = "+as",
|
||||
["$(PLATDEP)/msdos386/ncg"] = "+ncg",
|
||||
["$(PLATIND)/descr/msdos386"] = "./descr",
|
||||
"util/opt+pkg",
|
||||
}
|
||||
}
|
77
plat/msdos386/descr
Normal file
77
plat/msdos386/descr
Normal file
|
@ -0,0 +1,77 @@
|
|||
var w=4
|
||||
var wa=2
|
||||
var p=4
|
||||
var pa=2
|
||||
var s=2
|
||||
var sa=2
|
||||
var l=4
|
||||
var la=2
|
||||
var f=4
|
||||
var fa=2
|
||||
var d=8
|
||||
var da=2
|
||||
var x=8
|
||||
var xa=2
|
||||
var ARCH=i386
|
||||
var PLATFORM=msdos386
|
||||
var PLATFORMDIR={EM}/share/ack/{PLATFORM}
|
||||
var CPP_F=-D__MSDOS__ -D__DOS__ -D_DOS
|
||||
var ALIGN=-a0:2 -a1:2 -a2:2 -a3:2
|
||||
var MACHOPT_F=-m8
|
||||
var EGO_PLAT_FLAGS=-M{EM}/share/ack/ego/{ARCH}.descr
|
||||
|
||||
# Override the setting in fe so that files compiled for this platform can see
|
||||
# the platform-specific headers.
|
||||
|
||||
var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/share/ack/include/ansi
|
||||
|
||||
name be
|
||||
from .m.g
|
||||
to .s
|
||||
program {EM}/lib/ack/{PLATFORM}/ncg
|
||||
args <
|
||||
stdout
|
||||
need .e
|
||||
end
|
||||
name as
|
||||
from .s.so
|
||||
to .o
|
||||
program {EM}/lib/ack/{PLATFORM}/as
|
||||
args - -o > <
|
||||
prep cond
|
||||
end
|
||||
name led
|
||||
from .o.a
|
||||
to .out
|
||||
program {EM}/lib/ack/em_led
|
||||
mapflag -l* LNAME={PLATFORMDIR}/lib*
|
||||
mapflag -fp FLOATS={EM}/{ILIB}fp
|
||||
args {ALIGN} \
|
||||
({RTS}:.b=-u _i_main) \
|
||||
(.e:{HEAD}={PLATFORMDIR}/boot.o) \
|
||||
({RTS}:.ocm.bas.b={PLATFORMDIR}/c-ansi.o) \
|
||||
({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
|
||||
({RTS}:.mod={PLATFORMDIR}/modula2.o) \
|
||||
({RTS}:.p={PLATFORMDIR}/pascal.o) \
|
||||
-o > < \
|
||||
(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
|
||||
(.b:{TAIL}={PLATFORMDIR}/libb.a) \
|
||||
(.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \
|
||||
(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
|
||||
(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
|
||||
(.ocm.bas.mod.b.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
|
||||
{FLOATS?} \
|
||||
(.e:{TAIL}={PLATFORMDIR}/libem.a \
|
||||
{PLATFORMDIR}/libsys.a \
|
||||
{PLATFORMDIR}/libc.a \
|
||||
{PLATFORMDIR}/libem.a \
|
||||
{PLATFORMDIR}/libend.a)
|
||||
linker
|
||||
end
|
||||
name cv
|
||||
from .out
|
||||
to .exe
|
||||
program {EM}/bin/aslod
|
||||
args -p {PLATFORMDIR}/stub.exe < >
|
||||
outfile msdos386.exe
|
||||
end
|
6
plat/msdos386/include/ack/plat.h
Normal file
6
plat/msdos386/include/ack/plat.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef _ACK_PLAT_H
|
||||
#define _ACK_PLAT_H
|
||||
|
||||
#define ACKCONF_WANT_O_TEXT_O_BINARY 1
|
||||
|
||||
#endif
|
24
plat/msdos386/include/build.lua
Normal file
24
plat/msdos386/include/build.lua
Normal file
|
@ -0,0 +1,24 @@
|
|||
include("plat/build.lua")
|
||||
|
||||
headermap = {}
|
||||
packagemap = {}
|
||||
|
||||
local function addheader(h)
|
||||
headermap[h] = "./"..h
|
||||
packagemap["$(PLATIND)/msdos386/include/"..h] = "./"..h
|
||||
end
|
||||
|
||||
addheader("ack/plat.h")
|
||||
addheader("sys/types.h")
|
||||
|
||||
acklibrary {
|
||||
name = "headers",
|
||||
hdrs = headermap
|
||||
}
|
||||
|
||||
installable {
|
||||
name = "pkg",
|
||||
map = packagemap
|
||||
}
|
||||
|
||||
|
9
plat/msdos386/include/sys/types.h
Normal file
9
plat/msdos386/include/sys/types.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef _SYS_TYPES_H
|
||||
#define _SYS_TYPES_H
|
||||
|
||||
typedef long pid_t;
|
||||
typedef int mode_t;
|
||||
typedef long time_t;
|
||||
typedef long suseconds_t;
|
||||
|
||||
#endif
|
19
plat/msdos386/libsys/_hol0.s
Normal file
19
plat/msdos386/libsys/_hol0.s
Normal file
|
@ -0,0 +1,19 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .bss
|
||||
|
||||
! This data block is used to store information about the current line number
|
||||
! and file.
|
||||
|
||||
.define hol0
|
||||
.comm hol0, 8
|
18
plat/msdos386/libsys/brk.s
Normal file
18
plat/msdos386/libsys/brk.s
Normal file
|
@ -0,0 +1,18 @@
|
|||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
.define _brk
|
||||
_brk:
|
||||
mov ebx, esp
|
||||
mov eax, 1*4(ebx)
|
||||
callf (realloc_ptr)
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
|
35
plat/msdos386/libsys/build.lua
Normal file
35
plat/msdos386/libsys/build.lua
Normal file
|
@ -0,0 +1,35 @@
|
|||
acklibrary {
|
||||
name = "lib",
|
||||
srcs = {
|
||||
"./_hol0.s",
|
||||
"./brk.s",
|
||||
"./close.s",
|
||||
"./errno.s",
|
||||
"./getpid.s",
|
||||
"./isatty.s",
|
||||
"./rename.s",
|
||||
"./sbrk.c",
|
||||
"./sys_exists.s",
|
||||
"./sys_getdate.s",
|
||||
"./sys_gettime.s",
|
||||
"./sys_isopen.s",
|
||||
"./sys_isreadyr.s",
|
||||
"./sys_rawcreat.s",
|
||||
"./sys_rawlseek.s",
|
||||
"./sys_rawopen.s",
|
||||
"./sys_rawread.s",
|
||||
"./sys_rawwrite.s",
|
||||
"./sys_xret.s",
|
||||
"./unlink.s",
|
||||
"plat/msdos/libsys+srcs",
|
||||
},
|
||||
deps = {
|
||||
"lang/cem/libcc.ansi/headers+headers",
|
||||
"plat/msdos386/include+headers",
|
||||
"plat/msdos/libsys+headers",
|
||||
},
|
||||
vars = {
|
||||
plat = "msdos386"
|
||||
}
|
||||
}
|
||||
|
23
plat/msdos386/libsys/close.s
Normal file
23
plat/msdos386/libsys/close.s
Normal file
|
@ -0,0 +1,23 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Close a file.
|
||||
|
||||
.define _close
|
||||
_close:
|
||||
mov ebx, esp
|
||||
mov ebx, 1*4(esp)
|
||||
movb ah, 0x3E
|
||||
int 0x21
|
||||
jmp .sys_zret
|
28
plat/msdos386/libsys/errno.s
Normal file
28
plat/msdos386/libsys/errno.s
Normal file
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
#define D(e) .define e; e
|
||||
|
||||
.sect .data
|
||||
|
||||
! Define various ACK error numbers. Note that these are *not* ANSI C
|
||||
! errnos, and are used for different purposes.
|
||||
|
||||
D(ERANGE) = 1
|
||||
D(ESET) = 2
|
||||
D(EIDIVZ) = 6
|
||||
D(EHEAP) = 17
|
||||
D(EILLINS) = 18
|
||||
D(EODDZ) = 19
|
||||
D(ECASE) = 20
|
||||
D(EBADMON) = 25
|
||||
|
45
plat/msdos386/libsys/getpid.s
Normal file
45
plat/msdos386/libsys/getpid.s
Normal file
|
@ -0,0 +1,45 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Copyright (c) 2021--2022 TK Chia
|
||||
!
|
||||
! The authors hereby grant permission to use, copy, modify, distribute,
|
||||
! and license this software and its documentation for any purpose, provided
|
||||
! that existing copyright notices are retained in all copies and that this
|
||||
! notice is included verbatim in any distributions. No written agreement,
|
||||
! license, or royalty fee is required for any of the authorized uses.
|
||||
! Modifications to this software may be copyrighted by their authors
|
||||
! and need not follow the licensing terms described here, provided that
|
||||
! the new terms are clearly indicated on the first page of each file where
|
||||
! they apply.
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Get the current process identifier. For MS-DOS, use the Program Segment
|
||||
! Prefix (PSP) segment as the PID, unless the system supports an actual
|
||||
! `getpid' syscall, e.g. European MS-DOS 4.0.
|
||||
!
|
||||
! (Note that pid_t is a 32-bit type. This is to allow for PSP segments and
|
||||
! MS-DOS PIDs above 0x7FFF.)
|
||||
|
||||
.define _getpid
|
||||
_getpid:
|
||||
movb ah, 0x87
|
||||
stc
|
||||
int 0x21
|
||||
jnc .eur_dos
|
||||
movb ah, 0x51
|
||||
int 0x21
|
||||
xchg ebx, eax
|
||||
.eur_dos:
|
||||
xor edx, edx
|
||||
ret
|
37
plat/msdos386/libsys/isatty.s
Normal file
37
plat/msdos386/libsys/isatty.s
Normal file
|
@ -0,0 +1,37 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Say whether a given file descriptor number refers to a terminal.
|
||||
|
||||
.define _isatty
|
||||
_isatty:
|
||||
mov ebx, esp
|
||||
mov ebx, 4(ebx)
|
||||
o16 mov ax, 0x4400
|
||||
int 0x21
|
||||
jc error
|
||||
testb dl, dl
|
||||
jz not_tty
|
||||
mov eax, 1
|
||||
ret
|
||||
not_tty:
|
||||
mov (_errno), 25 ! ENOTTY
|
||||
not_tty_2:
|
||||
xor eax, eax
|
||||
ret
|
||||
error:
|
||||
push eax
|
||||
call __sys_seterrno
|
||||
pop ecx
|
||||
jmp not_tty_2
|
54
plat/msdos386/libsys/rename.s
Normal file
54
plat/msdos386/libsys/rename.s
Normal file
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Rename a file.
|
||||
|
||||
.define _rename
|
||||
_rename:
|
||||
mov ebx, esp
|
||||
push esi
|
||||
push edi
|
||||
|
||||
! Source filename.
|
||||
|
||||
mov esi, 4(ebx)
|
||||
movzx edi, (transfer_buffer_ptr)
|
||||
mov es, (pmode_ds)
|
||||
cld
|
||||
1:
|
||||
lodsb
|
||||
stosb
|
||||
testb al, al
|
||||
jnz 1b
|
||||
|
||||
! Destination filename.
|
||||
|
||||
mov eax, edi
|
||||
mov esi, 8(ebx)
|
||||
1:
|
||||
lodsb
|
||||
stosb
|
||||
testb al, al
|
||||
jnz 1b
|
||||
|
||||
! Make the DOS call.
|
||||
|
||||
o16 mov dx, (transfer_buffer_ptr)
|
||||
o16 mov di, ax
|
||||
movb ah, 0x56
|
||||
or ebx, 0x210000
|
||||
callf (interrupt_ptr)
|
||||
pop edi
|
||||
pop esi
|
||||
jmp .sys_zret
|
40
plat/msdos386/libsys/sbrk.c
Normal file
40
plat/msdos386/libsys/sbrk.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include "libsys.h"
|
||||
|
||||
extern char _end[1];
|
||||
static char* current = _end;
|
||||
|
||||
void* sbrk(int increment)
|
||||
{
|
||||
char* old;
|
||||
char* new;
|
||||
|
||||
if (increment == 0)
|
||||
return current;
|
||||
|
||||
old = current;
|
||||
|
||||
new = old + increment;
|
||||
|
||||
if ((increment > 0) && (new <= old))
|
||||
goto out_of_memory;
|
||||
else if ((increment < 0) && (new >= old))
|
||||
goto out_of_memory;
|
||||
|
||||
if (brk(new) < 0)
|
||||
goto out_of_memory;
|
||||
|
||||
current = new;
|
||||
return old;
|
||||
|
||||
out_of_memory:
|
||||
errno = ENOMEM;
|
||||
return OUT_OF_MEMORY;
|
||||
}
|
25
plat/msdos386/libsys/sys_exists.s
Normal file
25
plat/msdos386/libsys/sys_exists.s
Normal file
|
@ -0,0 +1,25 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Say whether a file exists with the given name.
|
||||
|
||||
.define __sys_exists
|
||||
__sys_exists:
|
||||
mov ebx, esp
|
||||
mov edx, 4(ebx)
|
||||
mov eax, 0x4300
|
||||
int 0x21
|
||||
sbb eax, eax
|
||||
inc eax
|
||||
ret
|
25
plat/msdos386/libsys/sys_getdate.s
Normal file
25
plat/msdos386/libsys/sys_getdate.s
Normal file
|
@ -0,0 +1,25 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Get the current system date from MS-DOS.
|
||||
|
||||
.define __sys_getdate
|
||||
__sys_getdate:
|
||||
movb ah, 0x2a
|
||||
int 0x21
|
||||
mov ebx, esp
|
||||
mov ebx, 4(ebx)
|
||||
o16 mov 0(ebx), dx
|
||||
o16 mov 2(ebx), cx
|
||||
ret
|
26
plat/msdos386/libsys/sys_gettime.s
Normal file
26
plat/msdos386/libsys/sys_gettime.s
Normal file
|
@ -0,0 +1,26 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Get the current system time from MS-DOS.
|
||||
|
||||
.define __sys_gettime
|
||||
__sys_gettime:
|
||||
int 3
|
||||
movb ah, 0x2c
|
||||
int 0x21
|
||||
mov ebx, esp
|
||||
mov ebx, 4(ebx)
|
||||
o16 mov 0(ebx), cx
|
||||
o16 mov 2(ebx), dx
|
||||
ret
|
26
plat/msdos386/libsys/sys_isopen.s
Normal file
26
plat/msdos386/libsys/sys_isopen.s
Normal file
|
@ -0,0 +1,26 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Say whether a given file descriptor number refers to a valid open file
|
||||
! descriptor.
|
||||
|
||||
.define __sys_isopen
|
||||
__sys_isopen:
|
||||
mov ebx, esp
|
||||
mov ebx, 4(bx)
|
||||
mov eax, 0x4400
|
||||
int 0x21
|
||||
sbb eax, eax
|
||||
inc eax
|
||||
ret
|
29
plat/msdos386/libsys/sys_isreadyr.s
Normal file
29
plat/msdos386/libsys/sys_isreadyr.s
Normal file
|
@ -0,0 +1,29 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Say whether a file descriptor is ready for input, i.e. reading from the
|
||||
! fd will immediately return something.
|
||||
|
||||
.define __sys_isreadyr
|
||||
__sys_isreadyr:
|
||||
mov ebx, esp
|
||||
mov eax, 0x4406
|
||||
mov ebx, 4(ebx)
|
||||
int 0x21
|
||||
jnc ok
|
||||
movb al, 0
|
||||
ok:
|
||||
o16 cbw
|
||||
cwde
|
||||
ret
|
45
plat/msdos386/libsys/sys_rawcreat.s
Normal file
45
plat/msdos386/libsys/sys_rawcreat.s
Normal file
|
@ -0,0 +1,45 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Create or truncate a file.
|
||||
|
||||
.define __sys_rawcreat
|
||||
__sys_rawcreat:
|
||||
! Copy filename to transfer buffer.
|
||||
|
||||
mov ebx, esp
|
||||
push esi
|
||||
push edi
|
||||
mov esi, 4(ebx)
|
||||
movzx edi, (transfer_buffer_ptr)
|
||||
mov es, (pmode_ds)
|
||||
cld
|
||||
1:
|
||||
lodsb
|
||||
stosb
|
||||
testb al, al
|
||||
jnz 1b
|
||||
|
||||
! Make the DOS call.
|
||||
|
||||
movb ah, 0x3c
|
||||
movzx edx, (transfer_buffer_ptr)
|
||||
movb al, 8(ebx)
|
||||
or ebx, 0x210000
|
||||
callf (interrupt_ptr)
|
||||
|
||||
pop edi
|
||||
pop esi
|
||||
jmp .sys_axret
|
||||
|
26
plat/msdos386/libsys/sys_rawlseek.s
Normal file
26
plat/msdos386/libsys/sys_rawlseek.s
Normal file
|
@ -0,0 +1,26 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Move the current file position for a file descriptor.
|
||||
|
||||
.define __sys_rawlseek
|
||||
__sys_rawlseek:
|
||||
movb ah, 0x42
|
||||
mov ebx, esp
|
||||
mov edx, 8(bx)
|
||||
mov ecx, 12(bx)
|
||||
movb al, 16(bx)
|
||||
mov ebx, 4(bx)
|
||||
int 0x21
|
||||
jmp .sys_dxaxret
|
45
plat/msdos386/libsys/sys_rawopen.s
Normal file
45
plat/msdos386/libsys/sys_rawopen.s
Normal file
|
@ -0,0 +1,45 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Open an existing file.
|
||||
|
||||
.define __sys_rawopen
|
||||
__sys_rawopen:
|
||||
! Copy filename to transfer buffer.
|
||||
|
||||
mov ebx, esp
|
||||
push esi
|
||||
push edi
|
||||
|
||||
mov esi, 4(ebx)
|
||||
movzx edi, (transfer_buffer_ptr)
|
||||
mov es, (pmode_ds)
|
||||
cld
|
||||
1:
|
||||
lodsb
|
||||
stosb
|
||||
testb al, al
|
||||
jnz 1b
|
||||
|
||||
! Make the DOS call.
|
||||
|
||||
movb ah, 0x3d
|
||||
o16 mov dx, (transfer_buffer_ptr)
|
||||
movb al, 8(ebx)
|
||||
or ebx, 0x210000
|
||||
callf (interrupt_ptr)
|
||||
|
||||
pop edi
|
||||
pop esi
|
||||
jmp .sys_axret
|
74
plat/msdos386/libsys/sys_rawread.s
Normal file
74
plat/msdos386/libsys/sys_rawread.s
Normal file
|
@ -0,0 +1,74 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Read bytes from a file descriptor. These routines do not do any
|
||||
! translation between CRLF and LF line endings.
|
||||
!
|
||||
! Note that, for MS-DOS, a raw "write" request of zero bytes will truncate
|
||||
! (or extend) the file to the current file position.
|
||||
|
||||
.define __sys_rawread
|
||||
__sys_rawread:
|
||||
enter 0, 0
|
||||
push esi
|
||||
push edi
|
||||
file_handle = 2*4
|
||||
write_buffer = 3*4
|
||||
amount_to_read = 4*4
|
||||
|
||||
mov eax, amount_to_read(ebp)
|
||||
mov ecx, 32*1024
|
||||
cmp eax, ecx
|
||||
jge 2f
|
||||
mov ecx, eax
|
||||
2:
|
||||
|
||||
! Read from DOS into the transfer buffer.
|
||||
|
||||
movb ah, 0x3f
|
||||
o16 mov dx, (transfer_buffer_ptr)
|
||||
o16 mov bx, file_handle(ebp)
|
||||
or ebx, 0x210000
|
||||
callf (interrupt_ptr)
|
||||
jnc success
|
||||
|
||||
! Process errors.
|
||||
|
||||
push eax
|
||||
call __sys_seterrno
|
||||
pop ecx
|
||||
jmp exit
|
||||
success:
|
||||
|
||||
! Copy eax bytes out of the transfer buffer.
|
||||
|
||||
push eax
|
||||
mov ecx, eax
|
||||
movzx esi, (transfer_buffer_ptr)
|
||||
mov edi, write_buffer(ebp)
|
||||
mov es, (pmode_ds)
|
||||
cld
|
||||
1:
|
||||
eseg lodsb
|
||||
movb (edi), al
|
||||
inc edi
|
||||
loop 1b
|
||||
pop eax
|
||||
|
||||
exit:
|
||||
pop edi
|
||||
pop esi
|
||||
leave
|
||||
ret
|
||||
|
66
plat/msdos386/libsys/sys_rawwrite.s
Normal file
66
plat/msdos386/libsys/sys_rawwrite.s
Normal file
|
@ -0,0 +1,66 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Write bytes to/to a file descriptor. These routines do not do any
|
||||
! translation between CRLF and LF line endings.
|
||||
!
|
||||
! Note that, for MS-DOS, a raw "write" request of zero bytes will truncate
|
||||
! (or extend) the file to the current file position.
|
||||
|
||||
.define __sys_rawwrite
|
||||
__sys_rawwrite:
|
||||
enter 0, 0
|
||||
push esi
|
||||
push edi
|
||||
file_handle = 2*4
|
||||
read_buffer = 3*4
|
||||
amount_to_write = 4*4
|
||||
|
||||
mov eax, amount_to_write(ebp)
|
||||
mov ecx, 32*1024 ! size of transfer buffer
|
||||
cmp eax, ecx
|
||||
jge 2f
|
||||
mov ecx, eax
|
||||
2:
|
||||
|
||||
! Copy ecx bytes into the transfer buffer.
|
||||
|
||||
push ecx
|
||||
mov esi, read_buffer(ebp)
|
||||
movzx edi, (transfer_buffer_ptr)
|
||||
mov es, (pmode_ds)
|
||||
cld
|
||||
rep movsb
|
||||
pop ecx
|
||||
|
||||
! Write from the transfer buffer to DOS.
|
||||
|
||||
movb ah, 0x40
|
||||
o16 mov dx, (transfer_buffer_ptr)
|
||||
o16 mov bx, file_handle(ebp)
|
||||
or ebx, 0x210000
|
||||
callf (interrupt_ptr)
|
||||
jnc exit
|
||||
|
||||
push eax
|
||||
call __sys_seterrno
|
||||
pop ecx
|
||||
exit:
|
||||
pop edi
|
||||
pop esi
|
||||
leave
|
||||
ret
|
||||
|
||||
! vim: sw=4 ts=4 et
|
||||
|
50
plat/msdos386/libsys/sys_xret.s
Normal file
50
plat/msdos386/libsys/sys_xret.s
Normal file
|
@ -0,0 +1,50 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! .sys_zret: if the carry flag is set, then set `errno' from the DOS error
|
||||
! code in ax, and return an int -1. If the carry flag is clear, just
|
||||
! return an int zero.
|
||||
!
|
||||
! .sys_axret: if the carry flag is set, then set `errno' from the DOS error
|
||||
! code in ax, and return a shortword -1. If the carry flag is clear, just
|
||||
! return ax as a return value.
|
||||
!
|
||||
! .sys_dxaxret: same as .sys_axret, but return -1 or dx:ax as a return value.
|
||||
|
||||
.extern .sys_zret
|
||||
.extern .sys_axret
|
||||
.extern .sys_dxaxret
|
||||
.sys_zret:
|
||||
jc error
|
||||
xor eax, eax
|
||||
no_error:
|
||||
ret
|
||||
|
||||
.sys_axret:
|
||||
jc error
|
||||
ret
|
||||
|
||||
.sys_dxaxret:
|
||||
jc error
|
||||
shl edx, 16
|
||||
o16 mov dx, ax
|
||||
mov eax, edx
|
||||
ret
|
||||
|
||||
error:
|
||||
movzx eax, ax
|
||||
push eax
|
||||
call __sys_seterrno
|
||||
pop ecx
|
||||
ret
|
44
plat/msdos386/libsys/unlink.s
Normal file
44
plat/msdos386/libsys/unlink.s
Normal file
|
@ -0,0 +1,44 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Remove a file.
|
||||
|
||||
.define _unlink
|
||||
_unlink:
|
||||
! Copy filename to transfer buffer.
|
||||
|
||||
mov ebx, esp
|
||||
push esi
|
||||
push edi
|
||||
|
||||
mov esi, 4(ebx)
|
||||
movzx edi, (transfer_buffer_ptr)
|
||||
mov es, (pmode_ds)
|
||||
cld
|
||||
1:
|
||||
lodsb
|
||||
stosb
|
||||
testb al, al
|
||||
jnz 1b
|
||||
|
||||
! Make the DOS call.
|
||||
|
||||
movzx edi, (transfer_buffer_ptr)
|
||||
movb ah, 0x41
|
||||
or ebx, 0x210000
|
||||
callf (interrupt_ptr)
|
||||
|
||||
pop edi
|
||||
pop esi
|
||||
jmp .sys_zret
|
410
plat/msdos386/stub.s
Normal file
410
plat/msdos386/stub.s
Normal file
|
@ -0,0 +1,410 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
.use16
|
||||
exe_header:
|
||||
.data2 0x5a4d ! magic number
|
||||
.data2 exe_last_page ! number of bytes in last loadable page
|
||||
.data2 exe_text_pages ! size of .exe, in pages
|
||||
.data2 0 ! number of relocation entries
|
||||
.data2 0 ! start of loadable area, in 16-byte paragraphs
|
||||
.data2 exe_ram_paras ! required RAM size, in 16-byte paragraphs
|
||||
.data2 exe_ram_paras ! maximum RAM siz, in 16-byte paragraphs
|
||||
.data2 0 ! initial SS, relative to program
|
||||
.data2 stack ! initial SP
|
||||
.data2 0 ! checksum (ignored)
|
||||
.data2 exe_start ! initial IP
|
||||
.data2 0 ! initial CS, relative to program
|
||||
.data2 0 ! offset of relocation table
|
||||
.data2 0 ! overlay number
|
||||
|
||||
exe_start:
|
||||
! On entry, DS=ES=PSP. Make DS=CS, so we're running in tiny mode.
|
||||
|
||||
push cs
|
||||
pop ds
|
||||
mov (rseg), ds
|
||||
mov (pspseg), es
|
||||
|
||||
! Ensure that at least two handles are available by blindly closing some.
|
||||
|
||||
mov bx, 19 ! close handle
|
||||
movb ah, 0x3e
|
||||
int 0x21
|
||||
mov bx, 18 ! close handle
|
||||
movb ah, 0x3e
|
||||
int 0x21
|
||||
|
||||
! Scan the environment to find the program name.
|
||||
|
||||
eseg mov es, (0x2c) ! environment pointer segment from PSP
|
||||
xor di, di
|
||||
xorb al, al
|
||||
mov cx, 0xffff
|
||||
cld
|
||||
1:
|
||||
repne scasb ! find end of next string
|
||||
eseg cmpb (di), 0
|
||||
jnz 1b
|
||||
2:
|
||||
add di, 3
|
||||
mov si, di
|
||||
repne scasb
|
||||
|
||||
! es:si now points at the program name, and es:di at one past the end.
|
||||
|
||||
mov cx, di
|
||||
sub cx, si
|
||||
sub sp, cx ! allocate space on stack
|
||||
mov di, sp ! es:si source, ds:di dest
|
||||
1:
|
||||
eseg movb al, (si)
|
||||
inc si
|
||||
movb (di), al
|
||||
inc di
|
||||
cmpb al, 0
|
||||
jnz 1b
|
||||
|
||||
! Open the file. (0x5f)
|
||||
|
||||
mov dx, sp
|
||||
mov ax, 0x3d00
|
||||
int 0x21
|
||||
jc no_file
|
||||
mov (fh), ax
|
||||
add sp, cx ! don't need filename any more
|
||||
|
||||
! Get the file length (== text len).
|
||||
|
||||
mov bx, ax
|
||||
mov ax, 0x4202
|
||||
xor cx, cx ! high offset
|
||||
xor dx, dx ! low offset
|
||||
int 0x21 ! lseek
|
||||
mov (pmemlen+0), ax
|
||||
mov (pmemlen+2), dx
|
||||
|
||||
! Initialise DPMI.
|
||||
|
||||
mov ax, 0x1687
|
||||
int 0x2f
|
||||
or ax, ax
|
||||
jnz no_dpmi
|
||||
mov (pmode_switch+0), di ! write back PMODE switch routine
|
||||
mov (pmode_switch+2), es
|
||||
or si, si ! do we need a DPMI private area?
|
||||
jz 1f
|
||||
|
||||
mov bx, si
|
||||
movb ah, 0x48
|
||||
int 0x21 ! allocate memory from DOS
|
||||
mov es, ax ! data area segment -> es
|
||||
1:
|
||||
! Switch to protected mode.
|
||||
|
||||
mov ax, 1 ! 32-bit app
|
||||
callf (pmode_switch)
|
||||
jc bad_dpmi
|
||||
|
||||
! We're now in protected mode.
|
||||
|
||||
mov (psegcs), cs
|
||||
mov (psegds), ds
|
||||
|
||||
! Allocate space for the code segment.
|
||||
|
||||
mov ax, 0x0000
|
||||
mov cx, 1
|
||||
int 0x31 ! allocate LDT
|
||||
jc bad_dpmi
|
||||
mov es, ax
|
||||
mov (psegcs32), ax
|
||||
|
||||
mov cx, (pmemlen+0)
|
||||
mov bx, (pmemlen+2)
|
||||
mov ax, 0x0501
|
||||
int 0x31 ! allocate linear address
|
||||
jc bad_dpmi
|
||||
mov (pmemhandle+0), di
|
||||
mov (pmemhandle+2), si
|
||||
|
||||
mov dx, cx
|
||||
mov cx, bx
|
||||
mov bx, es
|
||||
mov ax, 0x0007
|
||||
int 0x31 ! set segment base address
|
||||
jc bad_dpmi
|
||||
|
||||
mov bx, es
|
||||
mov dx, (pmemlen+0)
|
||||
mov cx, (pmemlen+2)
|
||||
mov ax, 0x0008
|
||||
int 0x31 ! set segment limit
|
||||
|
||||
mov cx, cs
|
||||
and cx, 3
|
||||
shl cx, 5
|
||||
or cx, 0xc09b ! 32-bit, big, code, non-conforming, readable
|
||||
mov bx, es
|
||||
mov ax, 0x0009
|
||||
int 0x31 ! set descriptor access rights
|
||||
|
||||
! Allocate the data segment (as a simple clone of the code segment). (10e)
|
||||
|
||||
mov ax, 0x000a
|
||||
mov bx, es
|
||||
int 0x31
|
||||
mov fs, ax
|
||||
mov (psegds32), ax
|
||||
|
||||
mov cx, ax
|
||||
and cx, 3
|
||||
shl cx, 5
|
||||
or cx, 0xc093 ! 32-bit, big, data, r/w, expand-up
|
||||
mov bx, fs
|
||||
mov ax, 0x0009
|
||||
int 0x31 ! set descriptor access rights
|
||||
|
||||
! Load the program.
|
||||
|
||||
mov bx, (fh)
|
||||
mov ax, 0x4200
|
||||
xor cx, cx ! high offset
|
||||
mov dx, text_top ! low offset
|
||||
int 0x21 ! lseek
|
||||
|
||||
o32 xor edi, edi ! destination 32-bit register
|
||||
1:
|
||||
movb ah, 0x3f
|
||||
mov bx, (fh)
|
||||
mov cx, TRANSFER_BUFFER_SIZE
|
||||
mov dx, transfer_buffer
|
||||
o32 push edi
|
||||
call int21 ! read up to 32kB into transfer buffer
|
||||
o32 pop edi
|
||||
cmp ax, 0
|
||||
je 2f
|
||||
|
||||
o32 movzx ecx, ax ! number of bytes read
|
||||
o32 mov esi, transfer_buffer
|
||||
cld
|
||||
o32 rep movsb
|
||||
jmp 1b
|
||||
2:
|
||||
|
||||
! Close the file.
|
||||
|
||||
movb ah, 0x3e
|
||||
mov bx, (fh)
|
||||
int 0x21 ! close
|
||||
|
||||
! Jump to the new segment and enter 32-bit mode!
|
||||
|
||||
o32 movzx eax, (psegcs)
|
||||
o32 movzx ebx, (psegds)
|
||||
o32 movzx ecx, (rseg)
|
||||
o32 mov edx, realloc
|
||||
o32 mov esi, interruptf
|
||||
o32 mov edi, transfer_buffer
|
||||
push es
|
||||
pop ds
|
||||
push es
|
||||
push 0
|
||||
retf ! 19b
|
||||
|
||||
! Helper routine which reallocates the linear block that the 32-bit code
|
||||
! is running from. This can't happen from inside the 32-bit code itself
|
||||
! because it might move.
|
||||
!
|
||||
! On entry, ds and ss are ignored. On exit, ds is set to the 32-bit segment.
|
||||
! eax: new block size
|
||||
realloc:
|
||||
cseg mov ds, (psegds)
|
||||
cli ! atomically switch stacks
|
||||
o32 mov (dpmi_ebp), esp ! yes, saving esp into the ebp field
|
||||
mov (dpmi_ss), ss
|
||||
mov ss, (psegds)
|
||||
mov sp, dosstack
|
||||
sti
|
||||
pusha
|
||||
|
||||
o32 add eax, 1024*1024 - 1
|
||||
o32 and eax, ~[1024*1024 - 1]
|
||||
o32 mov (pmemlen), eax
|
||||
mov cx, (pmemlen+0)
|
||||
mov bx, (pmemlen+2)
|
||||
mov di, (pmemhandle+0)
|
||||
mov si, (pmemhandle+2)
|
||||
mov ax, 0x0503
|
||||
int 0x31 ! resize memory block
|
||||
jc bad_dpmi
|
||||
mov (pmemhandle+0), di
|
||||
mov (pmemhandle+2), si
|
||||
mov (pmemaddr+0), cx
|
||||
mov (pmemaddr+2), bx
|
||||
|
||||
mov bx, (psegds32)
|
||||
mov dx, (pmemlen+0)
|
||||
mov cx, (pmemlen+2)
|
||||
mov ax, 0x0008
|
||||
int 0x31 ! set ds segment limit
|
||||
jc bad_dpmi
|
||||
mov dx, (pmemaddr+0)
|
||||
mov cx, (pmemaddr+2)
|
||||
mov ax, 0x0007
|
||||
int 0x31 ! set ds linear address
|
||||
jc bad_dpmi
|
||||
mov bx, (psegcs32)
|
||||
int 0x31 ! set cs linear address
|
||||
jc bad_dpmi
|
||||
|
||||
popa
|
||||
o32 mov eax, (pmemlen)
|
||||
cli ! atomically switch stacks back
|
||||
mov ss, (dpmi_ss)
|
||||
o32 mov esp, (dpmi_ebp)
|
||||
mov ds, (psegds32)
|
||||
sti
|
||||
|
||||
o32 retf
|
||||
|
||||
bad_dpmi:
|
||||
mov si, bad_dpmi_msg
|
||||
jmp exit_with_error
|
||||
|
||||
no_file:
|
||||
mov si, no_file_msg
|
||||
jmp exit_with_error
|
||||
|
||||
no_dpmi:
|
||||
mov si, no_dpmi_msg
|
||||
! fall through
|
||||
|
||||
! Displays the message in si and exits.
|
||||
! This uses a loop because from protected mode any interrupt which
|
||||
! takes a pointer parameter requires special treatment.
|
||||
exit_with_error:
|
||||
movb dl, (si)
|
||||
cmpb dl, 0
|
||||
je 1f
|
||||
inc si
|
||||
|
||||
movb ah, 2
|
||||
int 0x21 ! print character
|
||||
jmp exit_with_error
|
||||
1:
|
||||
mov ax, 0x4cff
|
||||
int 0x21 ! terminate with error code al
|
||||
|
||||
! Simulate DOS interrupt.
|
||||
int21:
|
||||
o32 or ebx, 0x210000
|
||||
! Simulate interrupt in the high half of ebx.
|
||||
interrupt:
|
||||
mov (dpmi_eax), ax
|
||||
mov (dpmi_ebx), bx
|
||||
mov (dpmi_ecx), cx
|
||||
mov (dpmi_edx), dx
|
||||
mov (dpmi_esi), si
|
||||
mov (dpmi_edi), di
|
||||
mov ax, (rseg)
|
||||
mov (dpmi_ds), ax
|
||||
mov (dpmi_ss), ax
|
||||
push es
|
||||
mov (dpmi_sp), dosstack ! auto stack is too small
|
||||
push ds
|
||||
pop es
|
||||
o32 mov edi, dpmi_edi
|
||||
mov ax, 0x300
|
||||
o32 shr ebx, 16
|
||||
int 0x31 ! simulate DOS interrupt
|
||||
pop es
|
||||
o32 movzx eax, (dpmi_eax)
|
||||
o32 movzx ebx, (dpmi_ebx)
|
||||
o32 movzx ecx, (dpmi_ecx)
|
||||
o32 movzx edx, (dpmi_edx)
|
||||
o32 movzx esi, (dpmi_esi)
|
||||
o32 movzx edi, (dpmi_edi)
|
||||
push (dpmi_flags)
|
||||
popf
|
||||
ret
|
||||
|
||||
! Far call wrapper around interrupt.
|
||||
interruptf:
|
||||
push ds
|
||||
cseg mov ds, (psegds)
|
||||
call interrupt
|
||||
pop ds
|
||||
o32 retf
|
||||
|
||||
bad_dpmi_msg:
|
||||
.asciz "DPMI error during setup"
|
||||
no_file_msg:
|
||||
.asciz "Couldn't open .exe"
|
||||
no_dpmi_msg:
|
||||
.asciz "No DPMI host installed"
|
||||
.align 4
|
||||
text_top:
|
||||
|
||||
exe_text_pages = [text_top - exe_header + 511] / 512
|
||||
exe_last_page = [text_top - exe_header] % 512
|
||||
|
||||
.sect .rom
|
||||
|
||||
.sect .bss
|
||||
bss_start:
|
||||
|
||||
dpmi_edi: .space 4
|
||||
dpmi_esi: .space 4
|
||||
dpmi_ebp: .space 4
|
||||
.space 4 ! reserved
|
||||
dpmi_ebx: .space 4
|
||||
dpmi_edx: .space 4
|
||||
dpmi_ecx: .space 4
|
||||
dpmi_eax: .space 4
|
||||
dpmi_flags: .space 2
|
||||
dpmi_es: .space 2
|
||||
dpmi_ds: .space 2
|
||||
dpmi_fs: .space 2
|
||||
dpmi_gs: .space 2
|
||||
dpmi_ip: .space 2
|
||||
dpmi_cs: .space 2
|
||||
dpmi_sp: .space 2
|
||||
dpmi_ss: .space 2
|
||||
|
||||
pmode_switch: .space 4
|
||||
rseg: .space 2 ! real mode
|
||||
pspseg: .space 2 ! real mode
|
||||
psegcs: .space 2 ! protected mode 16-bit code segment
|
||||
psegds: .space 2 ! protected mode 16-bit data segment
|
||||
psegcs32: .space 2 ! protected mode 32-bit code segment
|
||||
psegds32: .space 2 ! protected mode 32-bit data segment
|
||||
pmemaddr: .space 4 ! protected mode linear memory address
|
||||
pmemhandle: .space 4 ! protected mode linear memory handle
|
||||
pmemlen: .space 4 ! protected mode linear memory length
|
||||
fh: .space 2
|
||||
|
||||
.space 512
|
||||
stack:
|
||||
.space 512
|
||||
dosstack:
|
||||
|
||||
TRANSFER_BUFFER_SIZE = 32*1024
|
||||
transfer_buffer:
|
||||
.space TRANSFER_BUFFER_SIZE
|
||||
|
||||
bss_top:
|
||||
exe_ram_paras = [bss_top - bss_start + 15] / 16
|
||||
|
||||
! vim: ts=4 sw=4 et ft=asm
|
||||
|
|
@ -84,5 +84,5 @@ name cv
|
|||
mapflag -i LOD=amzlod
|
||||
program {EM}/bin/{LOD}
|
||||
args < >
|
||||
outfile msdos86.exe
|
||||
outfile msdos86.com
|
||||
end
|
||||
|
|
|
@ -3,42 +3,28 @@ acklibrary {
|
|||
srcs = {
|
||||
"./brk.c",
|
||||
"./close.s",
|
||||
"./creat.c",
|
||||
"./errno.s",
|
||||
"./getpid.s",
|
||||
"./gettimeofday.c",
|
||||
"./_hol0.s",
|
||||
"./isatty.s",
|
||||
"./kill.c",
|
||||
"./lseek.c",
|
||||
"./open.c",
|
||||
"./read.c",
|
||||
"./rename.s",
|
||||
"./setmode.c",
|
||||
"./signal.c",
|
||||
"./sys_exists.s",
|
||||
"./sys_fdmodes.c",
|
||||
"./sys_getdate.s",
|
||||
"./sys_getmode.c",
|
||||
"./sys_gettime.s",
|
||||
"./sys_initmain.c",
|
||||
"./sys_iseof.c",
|
||||
"./sys_isopen.s",
|
||||
"./sys_isreadyr.s",
|
||||
"./sys_rawcreat.s",
|
||||
"./sys_rawlseek.s",
|
||||
"./sys_rawopen.s",
|
||||
"./sys_rawrw.s",
|
||||
"./sys_seteof.c",
|
||||
"./sys_seterrno.c",
|
||||
"./sys_setmode.c",
|
||||
"./sys_xret.s",
|
||||
"./unlink.s",
|
||||
"./write.c",
|
||||
"plat/msdos/libsys+srcs",
|
||||
},
|
||||
deps = {
|
||||
"lang/cem/libcc.ansi/headers+headers",
|
||||
"plat/msdos86/include+headers",
|
||||
"plat/msdos/libsys+headers",
|
||||
},
|
||||
vars = {
|
||||
plat = "msdos86"
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include "libsys.h"
|
||||
|
||||
ssize_t write(int fd, void* buffer, size_t count)
|
||||
{
|
||||
static const char crlf[2] = "\r\n";
|
||||
int i;
|
||||
char *p, *q;
|
||||
size_t left, n;
|
||||
ssize_t r, tot;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (_sys_getmode(fd) == O_BINARY)
|
||||
return _sys_rawwrite(fd, buffer, count);
|
||||
|
||||
/* If the file descriptor is an O_TEXT fd, translate LFs to CRLFs. */
|
||||
p = buffer;
|
||||
left = count;
|
||||
tot = 0;
|
||||
while (left)
|
||||
{
|
||||
q = memchr(p, '\n', left);
|
||||
if (!q)
|
||||
return _sys_rawwrite(fd, p, left);
|
||||
|
||||
n = q - p;
|
||||
if (n)
|
||||
{
|
||||
r = _sys_rawwrite(fd, p, n);
|
||||
if (r <= 0)
|
||||
return tot ? tot : r;
|
||||
tot += r;
|
||||
p += r;
|
||||
left -= r;
|
||||
if (r != n)
|
||||
break;
|
||||
}
|
||||
|
||||
r = _sys_rawwrite(fd, crlf, sizeof crlf);
|
||||
if (r != 2)
|
||||
{
|
||||
if (r > 0)
|
||||
r = 0;
|
||||
return tot ? tot : r;
|
||||
}
|
||||
++tot;
|
||||
++p;
|
||||
--left;
|
||||
}
|
||||
return tot;
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
aslod \- ACK simple loader
|
||||
.SH SYNOPSIS
|
||||
.B aslod
|
||||
[\-h] [\-v] inputfile outputfile
|
||||
[\-h] [\-v] [\-p prefixfile] inputfile outputfile
|
||||
.SH DESCRIPTION
|
||||
.I aslod
|
||||
converts an absolute ack.out file into a simple binary memory dump.
|
||||
|
@ -16,5 +16,8 @@ The file must have all references resolved and be linked to a
|
|||
fixed address. aslod will dump the segments, in order, such
|
||||
that the first byte of TEXT is at offset 0 in the file
|
||||
(regardless of where it is in memory).
|
||||
.PP
|
||||
If a prefix file is specified, this is prepended to the output before writing.
|
||||
No changes to the output itself are made.
|
||||
.SH "SEE ALSO"
|
||||
ack.out(5)
|
||||
|
|
|
@ -37,6 +37,7 @@ struct outsect outsect[S_MAX];
|
|||
char* stringarea;
|
||||
|
||||
char* outputfile = NULL; /* Name of output file, or NULL */
|
||||
char* prefixfile = NULL; /* Name of prefix file, or NULL */
|
||||
char* program; /* Name of current program: argv[0] */
|
||||
|
||||
FILE* input; /* Input stream */
|
||||
|
@ -136,6 +137,19 @@ void emits(struct outsect* section, struct outsect* nextsect)
|
|||
}
|
||||
}
|
||||
|
||||
void emitprefixfile(void)
|
||||
{
|
||||
FILE* fp = fopen(prefixfile, "rb");
|
||||
|
||||
while (!feof(fp))
|
||||
{
|
||||
char buffer[BUFSIZ];
|
||||
size_t blocksize = fread(buffer, 1, BUFSIZ, fp);
|
||||
writef(buffer, 1, blocksize);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/* Macros from modules/src/object/obj.h */
|
||||
#define Xchar(ch) ((ch) & 0377)
|
||||
|
@ -204,6 +218,12 @@ int main(int argc, char* argv[])
|
|||
verbose = true;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
argv++;
|
||||
argc--;
|
||||
prefixfile = argv[1];
|
||||
break;
|
||||
|
||||
default:
|
||||
syntaxerror:
|
||||
fatal("syntax error --- try -h for help");
|
||||
|
@ -288,6 +308,8 @@ int main(int argc, char* argv[])
|
|||
|
||||
/* And go! */
|
||||
|
||||
if (prefixfile)
|
||||
emitprefixfile();
|
||||
emits(&outsect[TEXT], &outsect[ROM]);
|
||||
emits(&outsect[ROM], &outsect[DATA]);
|
||||
emits(&outsect[DATA], NULL);
|
||||
|
|
Loading…
Reference in a new issue