简体   繁体   English

C Inline ASM:将整数传递给寄存器

[英]C Inline ASM: passing integers to a register

I'm trying to make a simple kernel but I'm stucked on a cursor screen movement. 我正在尝试制作一个简单的内核,但我仍然坚持使用光标屏幕。 My function, for move the cursor, is written in Assembly, but the rest of the kernel is in C, so I have to make a C function for call that function. 我的函数,用于移动光标,是用汇编语言编写的,但是内核的其余部分都在C中,所以我必须为函数调用一个C函数。 And that's the C function: 这就是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");
}

In this function, I try to move the var unsigned int x to register bh and the other, unsigned int y , to register bl , and then call the function to move the cursor. 在这个函数中,我尝试将var unsigned int x移动到寄存器bh ,将另一个unsigned int y移动到寄存器bl ,然后调用该函数移动光标。

The problem is when I call this function, the cursor disappear from the screen. 问题是当我调用此函数时,光标从屏幕上消失。 I think the values x and y and registers values bl and bh are not the same. 我认为值xy以及寄存器值blbh是不一样的。 For give you an idea of that clue, I tested to pass values directly in the asm directive and it works: 为了让您了解该线索,我测试了直接在asm指令中传递值,它可以工作:

void setCursor(unsigned int x, unsigned int y) {
    asm("mov $1, %bl");
    asm("mov $2, %bh");
    asm("call set_cursor");
}

Any help is welcome. 欢迎任何帮助。 And thanks in advance. 并提前感谢。 :D :d

Assembly output from compiler Ubuntu 12.04 64bit compiling in 32bit 汇编输出编译器 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

Write the asm set_cursor function to use the CDECL calling convention and you can avoid the inline asm entirely. 编写asm set_cursor函数以使用CDECL调用约定,您可以完全避免使用内联asm。 Just use extern void set_cursor(int x, int y) and you can call it like any other C function. 只需使用extern void set_cursor(int x, int y) ,就可以像任何其他C函数一样调用它。 I use this for all asm in my own "kernel" (LGDT/IDT/etc). 我在我自己的“内核”(LGDT / IDT / etc)中使用这个asm。 The only exception being setting cr3 for paging, since it's so simple. 唯一的例外是将cr3设置为分页,因为它非常简单。

Assuming Intel syntax, you could add: 假设英特尔语法,您可以添加:

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

In your code, you seem to be accessing the wrong variable with %0 , since the position 0 of variables has been skipped, and usualy, you must set = to the destination variable. 在您的代码中,您似乎正在使用%0访问错误的变量,因为已跳过变量的位置0,并且通常必须将=设置为目标变量。

asm("mov (%1), %%bh" : : "r" (x) : "=bh");
                       |
                    %0 skipped

Also you can try to change the way you access registers: 您也可以尝试更改访问寄存器的方式:

register unsigned int *p0 asm ("r0") = x;

Read more here . 在这里阅读更多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM