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

时间:2016-10-22 08:36:36

标签: gcc inline-assembly compiler-bug

我有一段代码调用BIOS文本输出函数where jcr:path like '/apps/%'

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中。它省略了指令!它只是将它分开并且从不将任何字符存储到缓冲区中。

1 个答案:

答案 0 :(得分:3)

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

解决方案是将"S" (text) clobber添加到"memory"语句的clobber部分:

__asm__

这告诉编译器你依赖于内存值,并且你可能会更改内存值,因此在执行汇编语句之前确保内存是最新的应该是偏执的,并确保不依赖于任何内存它可能已缓存在寄存器中的值。有必要阻止编译器在我的代码中将存储区分为__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" );