繁体   English   中英

当我使用__asm__时,为什么gcc没有正确写入内存?

[英]Why is gcc not writing to memory correctly when I use __asm__

我有一段调用BIOS文本输出函数的代码, INT 0x10, AH=0x13

static void __stdcall print_raw(uint8_t row, uint8_t col, uint8_t attr,
                               uint16_t length, char const *text)
{
    __asm__ __volatile__ (
        "xchgw %%bp,%%si\n\t"
        "int $0x10\n\t"
        "xchgw %%bp,%%si\n\t"
        :
        : "d" (row | (col << 8)), "c" (length), "b" (attr), "a" (0x13 << 8), "S" (text)
    );
}

我有另一个功能,可以在屏幕上打印一个数字:

void print_int(uint32_t n)
{
    char buf[12];
    char *p;
    p = buf + 12;
    do {
        *(--p) = '0' + (n % 10);
        n /= 10;
    } while (p > buf && n != 0);

    print_raw(1, 0, 0x0F, (buf + 12) - p, p);
}

我花了很多时间试图找出为什么屏幕上没有任何东西出现。 我挖了它,看了为print_int生成的代码:

    .globl  print_int
    .type   print_int, @function
print_int:
.LFB7:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    $10, %ecx
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    pushl   %esi
    pushl   %ebx
    .cfi_offset 6, -12
    .cfi_offset 3, -16
    leal    -8(%ebp), %esi
    leal    -20(%ebp), %ebx
    subl    $16, %esp
    movl    8(%ebp), %eax
.L4:
    xorl    %edx, %edx
    decl    %esi
    divl    %ecx
    testl   %eax, %eax
    je  .L6
    cmpl    %ebx, %esi
    ja  .L4
.L6:
    leal    -8(%ebp), %ecx
    movl    $4864, %eax
    movb    $15, %bl
    movl    $1, %edx
    subl    %esi, %ecx
#APP
# 201 "bootsect.c" 1
    xchgw %bp,%si
    int $0x10
    xchgw %bp,%si

# 0 "" 2
#NO_APP
    addl    $16, %esp
    popl    %ebx
    .cfi_restore 3
    popl    %esi
    .cfi_restore 6
    popl    %ebp
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret

如果仔细观察L4的循环,你会发现它从未将任何东西存储到buf 它省略了指令! 它只是将它分开并且从不将任何字符存储到缓冲区中。

使用__asm__语句时,优化器可能会导致此类错误代码。 你需要非常小心你的约束。 在这种情况下,编译器没有“看到”我通过esi的指针访问内存,如"S" (text)输入约束中所指定的那样。

解决方案是在__asm__语句的clobber部分添加一个"memory" clobber:

__asm__ __volatile__ (
    "xchgw %%bp,%%si\n\t"
    "int $0x10\n\t"
    "xchgw %%bp,%%si\n\t"
    :
    : "d" (row | (col << 8)), "c" (length), "b" (attr), "a" (0x13 << 8), "S" (text)
    : "memory"
);

这告诉编译器你依赖于内存值,并且你可能会更改内存值,因此在执行汇编语句之前确保内存是最新的应该是偏执的,并确保不依赖于它可能的任何内存值缓存在寄存器中。 有必要防止编译器在我的代码中将存储区分为buf

暂无
暂无

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

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