【问题标题】:sdcc inline asm() not workingsdcc 内联 asm() 不工作
【发布时间】:2024-05-02 15:55:01
【问题描述】:

我正在使用 GCC(更正)SDCC 和 Eclipse IDE 来为 8051 架构嵌入式目标编译 C 代码。我需要插入一些 NOP 进行计时,而且我无法让编译器接受内联汇编代码。

使用__asm__ ("; This is a comment\nlabel:\n\tnop");(如下所示)或变体我得到警告112:函数'__asm__'隐式声明,然后错误101:参数过多,好像我正在尝试调用未声明的函数。我也尝试了SDCC manual 第 3.14 节中的所有其他选项。 __asm ... __endasm__asm 上给出语法错误,与单个下划线相同,并且空格、换行符或同一行的组合没有帮助。

如果我将 Makefile 中的命令行正确拼凑在一起(没有 #include 路径),SDCC 命令行上的 CFLAGS 是:

-Wp,-MD,$(@:%.rel=%.d),-MT,$@,-MP --disable-warning 110 -Wa,-p --model-medium

【问题讨论】:

  • 请展示你的整个函数和你用来编译这段代码的命令行。
  • 你说你为 8051 编译,你说 GCC。对我来说,这真的没有意义 - 或者现在是否有 8051 的 GCC 端口?您真正使用哪个编译器?你用mcs51gcc吗?顺便说一句,“标准语法”是什么意思? C89/C99/C11 没有定义内联汇编的语法。
  • AFAIK:要让 gcc 检测 asm 关键字,您需要在编译期间将 -std=gnu99 作为标志传递给 gcc
  • @Iwillnotexist_Idonotexist -- 感谢您的出色挖掘! _asm 表示已弃用,请改用 __asm,但仍然不起作用。 SDCC 帮助说它是 v3.1.0。我在编译器选项中没有看到任何内联汇编标志。
  • @Iwillnotexist_Idonotexist -- 做到了!我在手册中找到了preproc_asm 描述。它应该默认为“开”,但似乎没有。 +- 似乎也可以工作。请把它放在答案中,我会投票赞成。如果没有你的帮助,我根本无法解决这个问题!

标签: c inline-assembly sdcc


【解决方案1】:

comment移动

sources of SDCC 3.1.0 的词法分析器中,我看到_asm/_endasm__asm/__endasm 都受支持。我还没有注意到解析器中对__asm("string") 的支持。

同样在词法分析器的代码中,内联程序集标记“blob”的词法分析类型更改为CPP_ASM 仅当一个名为preproc_asm 的属性设置为0,如可以见sdcc/support/cpp/libcpp/lex.c:1900

      result->type = CPP_NAME;
      {
        struct normalize_state nst = INITIAL_NORMALIZE_STATE;
        result->val.node.node = lex_identifier (pfile, buffer->cur - 1, false,
                                                &nst);
        warn_about_normalization (pfile, result, &nst);
      }

      /* SDCC _asm specific */
      /* handle _asm ... _endasm ;  */
      if (result->val.node.node == pfile->spec_nodes.n__asm || result->val.node.node == pfile->spec_nodes.n__asm1)
        {
          if (CPP_OPTION (pfile, preproc_asm) == 0)
            {
              comment_start = buffer->cur;
              result->type = CPP_ASM;
              _sdcpp_skip_asm_block (pfile);
              /* Save the _asm block as a token in its own right.  */
              _sdcpp_save_asm (pfile, result, comment_start, result->val.node.node == pfile->spec_nodes.n__asm);
            }
          result->flags |= ENTER_ASM;
        }
      else if (result->val.node.node == pfile->spec_nodes.n__endasm || result->val.node.node == pfile->spec_nodes.n__endasm1)
        {
          result->flags |= EXIT_ASM;
        }
      /* Convert named operators to their proper types.  */
      else if (result->val.node.node->flags & NODE_OPERATOR)
        {
          result->flags |= NAMED_OP;
          result->type = (enum cpp_ttype) result->val.node.node->directive_index;
        }
      break;

解决方案是在文件顶部添加#pragma preproc_asm -(或+)并使用多行__asm/__endasm 块。

【讨论】:

  • @CarpeCimex 我冒昧地包含了相关的词法分析器源代码,它让我意识到#pragma preproc_asm (+|-) 的相关性。
  • @Iwillnotexist_Idonotexist #pragma preproc_asm + 在文件的顶部和一个多行的__asm ... __endasm 汇编块就像在manual 中的第51 页的顶部一样。非常感谢!
  • @CarpeCimex 再想一想:代码只是编译还是nops实际存在于二进制输出中?
  • @Iwillnotexist_Idonotexist :-) 我也担心这个,而且确实汇编代码出现在汇编列表中。
【解决方案2】:

此链接:http://www.crossware.com/smanuals/c8051/_t243.html

关于内联汇编代码有什么要说的

可以通过两种方式将汇编代码嵌入到您的 C 源代码中:

using the #asm/#endasm preprocessor directives
using the _asm keyword

预处理器指令#asm 和#endasm 允许将汇编代码包含在C 源代码文件中的任何位置,唯一的限制是它不能定位在表达式中。 #asm 和#endasm 之间的所有行都未经修改直接传递到汇编程序处理的中间文件,因此支持跨汇编程序源代码的所有规则。

预处理器指令#if、#ifdef、#ifndef、#else、#elif 和#endif 在#asm 和#endasm 之间有效,因此可以在需要时用于维护汇编代码。

_asm 关键字只能在函数中使用。它与以下语法一起使用:

_asm();

字符串常量以单行的形式直接传递给汇编程序处理的中间文件。因此,每个都应该是有效的汇编代码行。

_asm 语法的一个优点是它可以被 C 预处理器替换。因此语句可以由一系列宏生成。

同样使用 _asm 语法,编译器支持一种特殊的结构,可以轻松访问 C 变量。如果变量名放在大括号内的字符串常量中,编译器会根据变量的位置用适当的子字符串替换变量名(和大括号)。有关详细信息,请参阅以下部分。

编译器生成大写助记符,因此如果为内联汇编代码选择小写,则可以清楚地区分编译器在列表文件中生成的代码。

然而,正确的格式是:'_asm("nop");'因为助记汇编指令不能是一行的第一件事(该特权用于标签)

【讨论】:

  • 问题是关于 GCC 的。您链接到其他系统的参考。
  • 为捍卫答案,afaik GCC 不支持 8051,问题也与 8051 有关。我会说部分不清楚这家伙到底在问什么。
最近更新 更多