1 攻克难题——字符串显示API(harib18a)
早安,大家精神还好吗?笔者有点没睡够,不过今天我们要继续加油哦。
先总结一下昨天最后遇到的情况:hello.hrb运行正常,但hello2.hrb却出现异常。为什么会这样呢?想了一下,应该是内存段惹的祸。
显示单个字符时,我们用[CS:ECX]的方式特意指定了CS(代码段寄存器),因此可以成功读取msg的内容。但在显示字符串时,由于无法指定段地址,程序误以为是DS而从完全错误的内存地址中读取了内容,碰巧读出的内容是0,于是就什么都没有显示出来。
因此,我们需要在API中做个改动,使其能够将应用程序传递的地址解释为代码段内的地址。
■■■■■
hrb_api并不知道代码段的起始位置位于内存的哪个地址,但cmd_app应该知道,因为当初设置这个代码段的正是cmd_app。
由于我们没有办法从cmd_app向hrb_api直接传递数据,因此只好又在内存里找个地方存放一下了。0xfec这个位置之前已经用过了,这次我们放在它前面的0xfe8好了。
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline)
{
(中略)
if (finfo != 0) {
/*找到文件的情况*/
p = (char *) memman_alloc_4k(memman, finfo->size);
*((int *) 0xfe8) = (int) p; /*这里! */
file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));
set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER);
farcall(0, 1003 * 8);
memman_free_4k(memman, (int) p, finfo->size);
cons_newline(cons);
return 1;
}
/*没有找到文件的情况*/
return 0;
}
void hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
int cs_base = *((int *) 0xfe8); /*这里!*/
struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);
if (edx == 1) {
cons_putchar(cons, eax & 0xff, 1);
} else if (edx == 2) {
cons_putstr0(cons, (char *) ebx + cs_base); /*这里!*/
} else if (edx == 3) {
cons_putstr1(cons, (char *) ebx + cs_base, ecx); /*这里!*/
}
return;
}
就是这个样子,应该没有什么难点,所以就不讲解了。
好了,赶紧试验一下,看看只有19个字节的hello2能不能成功显示出字符串。
显示出来了!
成功了,看来果然是内存段搞的鬼,问题解决!