【问题标题】:"undefined named operand" error in arm64 inline assemblyarm64 内联汇编中的“未定义的命名操作数”错误
【发布时间】:2022-01-14 21:26:21
【问题描述】:

这是我用来在内存中写入一些数据以进行调试的代码(直到 printf 在 u-boot 程序中可用)。变量myptr 位于.__mydebug 部分,每写入8 字节后它就增加8,我想以{debug_tag, debug_value} 对的形式写入我感兴趣的任何值。这里debug_tag 是显示调试数据序列的一些值,debug_value 是我在调试期间要检查(或查看)的值。这是 arm64 程序集。

.global myptr

ldr x28, =myptr   /* load the address of myptr */
add x28, x28, #8  /* set write pointer to the next address after the myptr variable */
mov x27, #0x33   /* first debug write starts with tag value 0x33 */
str x27, [x28], #8   /* write the tag value, increment the pointer */
mov x27, some_value   /* some_value : the value I want to see with tag value 0x33 */
str x27, [x28], #8   /* write the debug value, increment the pointer */    ldr x26, =myptr    /* load pointer address */


/* next debug write, in the same assembly code, x28 hasn't changed, so use as is */
mov x27, #0x34  /* new debug tag */
str x27, [x28], #8  /* write new tag, increment pointer */
mov x27, some_another_value  /* another data I want to check */
str x27, [x28], #8  /* write the data, increment pointer */
ldr x26, =myptr  /* load the address of myptr to x26 */
str x28, [x26]   /* save the updated pointer in myptr, just in case x28 is modified and \
                   the pointer should be used later in assembly or C code .. */
.... (skip) ....

.section .__mydebug
myptr: .double 0x0
data_start: .double 0x0

所以这是在一个有效的内存部分中顺序写入调试信息。
我可以稍后在 .c 程序中继续此调试写入,如下所示,它也可以工作。

// debug print 
int xx=sizeof(struct global_data);
*((uint64_t *)myptr) = 0x101; myptr+=8;  /* debug tag start with 0x101 here */
*((uint64_t *)myptr) = xx; myptr+=8;     /* write some data I want to check.. */
*((uint64_t *)myptr) = 0x102; myptr+=8;  /* another debug tag */
*((uint64_t *)myptr) = base; myptr+=8;    /* another value I want to check */

好吧,我可以忍受。但这看起来不太好也不方便。
所以我很好奇如何在 C 程序中使用带有内联汇编的函数来完成上述操作。我想将标记值和调试值(64 位)作为参数传递给函数。该函数应检索myptr 值以写入标签和数据,并应每次更新myptr 值。我试着在下面写一个函数。

void dbg_print(unsigned int tag, uint64_t data)
{
    uint64_t ptr_addr1;
__asm (
    "ldr %[ptr_addr], =myptr" \
    "ldr %[ptr_val], [%[ptr_addr]]" \
    "str %[tag_val], [%[ptr_val]], #8" \
    "str %[data_val], [%[ptr_val]], #8"
    : /* no output */ \
    : [tag_val] "r" (tag), [data_val] "r" (data) /* input list */ \
    : "memory" /* no specific clobbered register, but memory modified */
);
}

当我编译它时,我得到这个编译错误。

common/init/board_init.c: In function 'dbg_print':
common/init/board_init.c:144:1: error: undefined named operand 'ptr_addr'
  144 | );
      | ^
common/init/board_init.c:144:1: error: undefined named operand 'ptr_val'
common/init/board_init.c:144:1: error: undefined named operand 'ptr_addr'
common/init/board_init.c:144:1: error: undefined named operand 'ptr_val'
common/init/board_init.c:144:1: error: undefined named operand 'ptr_val'
make[2]: *** [scripts/Makefile.build:254: spl/common/init/board_init.o] Error 1
make[1]: *** [scripts/Makefile.spl:515: spl/common/init] Error 2

我无法理解undefined named operand 错误。我需要在模板中的某处定义操作数吗?在https://www.keil.com/support/man/docs/armclang_ref/armclang_ref_qbn1517569205870.htm 的示例中,模板中的操作数只是使用而没有定义。 C 中的变量无论如何都被声明了,但汇编模板中的操作数不是被编译器替换了吗?
感谢您的阅读,如果有人能向我澄清这件事,我将不胜感激。

添加:
在阅读了 Nate Eldredge 和 Peter Cordes 的 cmets 后,我意识到“定义操作数”意味着使用操作数说明符将值连接到 C 世界(那些在 : 之后并与 : 连接的字段)。所以我尝试将代码更改为此,我会看看这是否有效。

void dbg_print(unsigned int tag, uint64_t data)
{
    uint64_t ptra, ptrv;
__asm (
    "ldr %[ptr_addr], =myptr \n"   /* get pointer address */
    "ldr %[ptr_val], [%[ptr_addr]] \n"    /* get pointer value */
    "str %[tag_val], [%[ptr_val]], #8 \n"   /* write to pointed addr */
    "str %[data_val], [%[ptr_val]], #8 \n"   /* write to pointed addr */
    : [ptr_addr] "=r" (ptra), [ptr_val] "=r" (ptrv)
    : [tag_val] "r" (tag), [data_val] "r" (data) /* input list */
    : "memory" /* no specific clobbered register, but memory modified */
    );
}

【问题讨论】:

  • 我不确定为什么要使用内联汇编来进行编译器可以很好地完成的简单加载和存储。你可以更简洁地写成volatile uint64_t *p = (volatile uint64_t *)myptr; p[0] = 0x101; p[1] = xx; p[2] = 0x102; p[3] = base; 或者将它包装在一个不错的函数或宏中。
  • 在示例中,模板中的操作数不只是使用而不定义;模板中的名称lhsrhs 与最后为操作数指定的名称相匹配。您的代码没有定义任何名为 ptr_addr 的操作数,因此它不起作用。如果您想知道,它不会自动与具有该名称的程序变量匹配。
  • 如果我正确理解代码,实际上应该是volatile uint64_t *p = (volatile uint64_t *)&myptr;
  • 您指定的命名操作数是[data_val][tag_val],而不是[ptr_addr][ptr_val],所以错误信息看起来很明显; GCC 不知道如何扩展 %[ptr_addr],因为您没有在 Extended Asm 语句中给出任何操作数的名称。正如 Nate 所说,最好的解决办法可能是完全替换 inline-asm 语句。特别是因为你有像写寄存器这样的错误,但没有指定任何"=r" 输出操作数,只有"r" 输入(这意味着只读)。
  • 嗨,Nate 和 Peter,感谢 cmets。我以前曾多次得到你的帮助(:))。我更新了我的问题,如果它有效,我会尝试。顺便说一句,我只是想在这种情况下使用使用内联汇编的函数。 (更清楚地理解)。

标签: assembly gcc inline-assembly arm64


【解决方案1】:

我无法理解未定义的命名操作数错误。我需要在模板中的某处定义操作数吗?在https://www.keil.com/support/man/docs/armclang_ref/armclang_ref_qbn1517569205870.htm的例子中,模板中的操作数是直接使用的,没有定义。

是的,您需要在 asm 语句的输入或输出中定义它们。您链接的示例都定义了它们使用的所有名称。您的代码只是在那里定义了tag_valdata_val,所以ptr_valptr_addr 是未定义的。

【讨论】:

  • 我是从 Peter Cordes 的评论中学到的,但因为这是原始问题,所以我选择它作为答案。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-11
  • 2019-02-17
  • 2016-09-11
相关资源
最近更新 更多