2010-08-15 29 views
3

我正在为8086处理器编写小内核(在BC3.1中,在Windows XP上作为主机操作系统工作)。内核是多线程的,所以当我使用printf或cout进行调试时(在代码中的某处,printf将InterruptEnable标志设置为1,并且我的计时器中断例程调用了调度并且代码崩溃),我遇到了问题。Borland C++ inline asm问题,用WORD PTR和字符串

正因为如此,我在联汇编写的简单puts功能:

void _printf(char *c) 
{ 
    //setup data 
    asm{ 
     mov ch, 10 
     mov cl, 0 
     mov ah, 0x2 
     mov bx, WORD PTR c 
    } 

    loop: asm{ 
       //\0? 
       cmp [bx], cl 
       je exit_prc 
       mov dl, [bx] 
       int 0x21 
       inc bx 
       //is there \n? 
       cmp [bx], ch 
       je newline 

       jmp loop 
    } 
    exit_prc: return; 
    newline: asm{ 
       //insert cr char 
       mov dl, 0xD 
       int 21h 
       jmp loop 
    } 


} 

现在,我什么地方调用它,可以说PCB :: PCB()这样的:
_printf(“Counstructor PCBA \ n“);
它工作正常。但是,当我将它称为其他地方时,在其他字符串的其他文件中输出例如“tructor PCBa \ n”。

我不知道发生了什么。内存模型非常庞大。

+0

要调用此从定时器ISR? DOS不可重入。 – 2010-08-15 17:21:28

+0

否定时器ISR只做上下文切换。我可能有20多个线程,并且我也有信号量和事件实现。所以,当我的应用程序挂在一些执行不当的wait()时,我无法使用调试器对其进行跟踪,我唯一的选择是在代码中显示队列大小/元素和当前行以及线程ID。但是,如果我使用标准puts()来执行此操作,则我的Timer ISR会在puts内部的某处被调用,并且会导致在没有调试器的情况下运行时未运行的上下文切换。 – 2010-08-15 19:32:32

回答

2

首先,至少在我看来,你选择了一个相当可怜的名字 - 你所拥有的几乎是puts,而不是printf。其次,对于你想要完成的任务,你可能想要尝试使用Borland的cprintf,cputs等等 - 它们使用DOS控制台输出例程,并且他们不允许中断的可能性相当大。

如果这不起作用,似乎还没有什么理由使用内联汇编。我会做这样的事情:

// warning: untested -- and it's been a while since I wrote any code like this, 
// so it's probably a little wrong. 
// 
void myputc(char ch) { 
    union REGS in, out; 

    // set up registers here: 
    in.h.ah = 2; 

    in.h.dl = ch; 
    intdos(&in, &out); 
} 

void myputs(char huge *s) { 
    while (*s) { 
     if (*s == '\n') 
      myputc('\r'); 
     myputc(*s++); 
    } 
}    

如果你真的想用汇编语言,我的建议是把它写的纯汇编语言的一个单独的模块:

; Again: not tested and I haven't done this in a while, so use with care. 
; 
.model large, c 

.code 

LF = 10 
CR = 13 

putc proc 
    mov dl, al 
    mov ah, 2 
    int 21h 
    ret 
putc endp 

puts proc string: ptr char 
    mov si, string 
    lodsb 
next: 
    cmp al, LF 
    jnz printit 
    mov dl, CR 
    mov ah, 2 
    int 21h 
printit: 
    mov dl, al 
    mov ah, 2 
    int 21h 
    lodsb 
    test al, al 
    jnz next 
    ret 
puts endp 
    end   
+0

谢谢你,工作!它只会用于调试,没有别的,所以我不在乎函数的名称(我看到我错了)。 这个REGS联盟似乎很有趣 - 我会检查一下,看起来非常有用。现在我看到我没有检查dos.h函数有多大的错误。 注:如果有人试图使用杰里的代码,有一个s ++滑倒。 – 2010-08-15 19:27:42

+0

@Burgos:哎呀,很对。我已经添加了增量。 – 2010-08-15 19:40:44