我正在尝试创建一个简单的内核,但我仍然坚持使用光标屏幕移动。 我的函数,用于移动光标,是用汇编语言编写的,但是内核的其余部分都在C中,所以我必须为函数调用一个C函数。这就是C函数:
void setCursor(unsigned int x, unsigned int y) {
asm("mov (%0), %%bl" :: "r" (y) : "%bl");
asm("mov (%0), %%bh" :: "r" (x) : "%bh");
asm("call set_cursor");
}
在此函数中,我尝试将var unsigned int x
移动到注册bh
,将另一个unsigned int y
移动到注册bl
,然后调用该函数移动光标。
问题是当我调用此功能时,光标从屏幕上消失。我认为值x
和y
以及值bl
和bh
的值不一样。为了让您了解该线索,我测试了直接在asm指令中传递值,它可以工作:
void setCursor(unsigned int x, unsigned int y) {
asm("mov $1, %bl");
asm("mov $2, %bh");
asm("call set_cursor");
}
欢迎任何帮助。并提前感谢。 :d
编译器的汇编输出 Ubuntu 12.04 64位编译在32位
setCursor:
.LFB12:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
movl 12(%ebp), %eax
pushl %ebx
.cfi_offset 3, -12
#APP
# 131 "./kernel/screen.c" 1
mov (%eax), %bl
# 0 "" 2
#NO_APP
movl 8(%ebp), %eax
#APP
# 132 "./kernel/screen.c" 1
mov (%eax), %bh
# 0 "" 2
# 133 "./kernel/screen.c" 1
call set_cursor
# 0 "" 2
#NO_APP
popl %ebx
.cfi_restore 3
popl %ebp
.cfi_def_cfa 4, 4
.cfi_restore 5
ret
.cfi_endproc
答案 0 :(得分:4)
编写asm set_cursor函数以使用CDECL调用约定,您可以完全避免使用内联asm。只需使用extern void set_cursor(int x, int y)
,就可以像任何其他C函数一样调用它。我在我自己的内核中使用这个asm"内核" (LGDT / IDT /等)。唯一的例外是将cr3设置为分页,因为它非常简单。
假设使用英特尔语法,您可以添加:
set_cursor:
mov ecx, [esp + 4] # x in ecx (args are pushed right to left)
mov edx, [esp + 8] # y in edx
push ebx # ebx has to be preserved in CDECL
mov bh, cl
mov bl, dl
# Your original code...
pop ebx
ret
答案 1 :(得分:0)
在您的代码中,您似乎使用%0
访问了错误的变量,因为已跳过变量的位置0,并且通常必须将=
设置为目标变量。
asm("mov (%1), %%bh" : : "r" (x) : "=bh");
|
%0 skipped
您也可以尝试更改访问寄存器的方式:
register unsigned int *p0 asm ("r0") = x;
了解更多here。