当前位置: 首页 > 知识库问答 >
问题:

AVR-GCC内联汇编中输出寄存器的使用有哪些限制?

谭修竹
2023-03-14
uint8_t one ()
{
    uint8_t res;
    asm("ldi %[res],0\n"
        "inc %[res]\n"
        : [res] "=r" (res)
    );
    return res;
}

我看到的问题是,当我将内联asm改为直接在输出寄存器上工作时,它会中断,而不是使用r16进行计算,最后将r16移动到输出寄存器中。代码在这里:http://ideone.com/jtpyma。它将结果打印成串行,您只需要定义F_CPU和baud。该问题仅在使用GCC-4.8.0而不使用GCC-4.7.2时才出现。

[1]http://www.nongnu.org/avr-libc/user-manual/inline_asm.html

共有1个答案

陆绍辉
2023-03-14

编译器并不关心你读不读它,它只是不会把变量的初始值放入寄存器中。您的示例完全合法,但人们通常错误地期望从此代码中得到结果2:

uint8_t one ()
{
    uint8_t res = 1;
    asm("inc %[res]\n"
        : [res] "=r" (res)
    );
    return res;
}

由于它只是一个输出约束,res的初始值不能保证加载到寄存器中。事实上,初始化器甚至可以在假定asm块无论如何都会覆盖它的情况下被优化掉。以上代码是由我的AVR-GCC版本编译成这样的:

inc r24
ret

正如您所看到的,编译器确实删除了将1加载到res中,从而将其加载到r24中,从而产生未定义的结果。

问题中更新的程序的问题是它还有一个输入寄存器操作数。默认情况下,编译器假定所有输入都在分配输出之前被消耗,因此分配重叠寄存器是安全的。你的例子显然不是这样。您应该为输出使用一个“Early Clobber”修饰符(&)。这就是《手册》要说的:

&表示(在一个特定的替代方案中)这个操作数是一个earlyclobber操作数,它在指令使用输入操作数完成之前被修改。因此,该操作数可能不位于用作输入操作数或作为任何存储器地址的一部分的寄存器中。

没有人说gcc内联asm很容易:d

 类似资料:
  • 问题内容: 溢出, 如何仅使用内联汇编实现putchar(char)过程?我想在x86-64汇编中做到这一点。我这样做的原因是实现我自己的标准库(或至少一部分)。这是我到目前为止的内容: 我正在编译: 感谢您的帮助! 问题答案: 使用GNU C内联asm时,请 使用约束来告诉编译器您想要的东西 ,而不是使用asm模板中的指令“手动”进行。 对于和,我们只需要为模板,用约束来设置所有寄存器输入(与所

  • GCC扩展内联汇编 使用GCC扩展内联汇编的例子如下: #define read_cr0() ({ \ unsigned int __dummy; \ __asm__( \ "movl %%cr0,%0\n\t" \ :"=r" (__dummy)); \ __dummy; \ }) 它代表什么含义呢?这需要从其基本格式讲起。GCC扩展内联汇编的基本格式是: asm [volat

  • GCC基本内联汇编 GCC 提供了两内内联汇编语句(inline asm statements):基本内联汇编语句(basic inline asm statement)和扩展内联汇编语句(extended inline asm statement)。GCC基本内联汇编很简单,一般是按照下面的格式: asm("statements"); 例如: asm("nop"); asm("

  • 我正在为一个操作系统分配编写内联汇编代码。我有一些关于内联汇编和gcc编译器将其转换为机器代码的问题。 null

  • 问题内容: 说,我想在gcc的内联汇编中调用具有以下签名的函数。我怎样才能做到这一点? 问题答案: 通常,您会想要做类似的事情 也就是说,您根本不需要在嵌入式asm中进行函数调用。这样,您不必担心调用约定或堆栈框架管理的细节。

  • 问题内容: 是否可以从内联汇编块中使用syscall编写单个字符?如果是这样,怎么办?它应该看起来像“东西”: $ 80是ascii中的“ P”,但是什么也不会返回。 任何建议,不胜感激! 问题答案: 就像是 添加 :请注意,我曾经将char的有效地址加载到寄存器中;对于我尝试$ 0和$ 1的价值,它似乎仍然可以工作… 避免使用外部字符 注意:它之所以有效是因为Intel处理器的字节序!:D