SDCC内联汇编(inline asm())无法工作

4
我正在使用Eclipse IDE以及SDCC编译器来编译适用于8051架构嵌入式目标的C代码。 我需要插入一些NOP进行时间控制,但无法让编译器接受内联汇编代码。
在下面建议的方式中使用“__asm__(”;这是一个注释\nlabel:\n\t nop“);或类似的变化时,会出现“警告112:函数'__asm__'隐式声明”,然后出现“错误101:参数太多” ,就好像我试图调用未声明的函数一样。 我也尝试了{{link1:SDCC手册}}第3.14节中的所有其他选项。 __asm ... __endasm在__asm上给出语法错误,单个下划线也是如此,并且空格,换行符或同一行的组合都没有帮助。
如果我正确地从Makefile中拼接命令行(不包括#include路径),则SDCC命令行中的CFLAGS为:

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

这是一串编译器的参数,大致意思为:禁用警告110,使用中等模型,生成依赖关系文件。

2
请展示您的整个函数以及编译此代码所使用的命令行。 - Carl Norum
2
你说你要为8051编译,而且你还说用的是GCC。对我来说这并不太合理——难道现在有针对8051的GCC移植版了吗?你真正使用的编译器是哪个?你使用的是mcs51gcc吗?顺便问一下,“标准语法”是什么意思?C89/C99/C11并没有定义内联汇编的语法。 - Christian Hujer
1
据我所知:为了让gcc检测到asm关键字,在编译期间需要将-std=gnu99作为标志传递给gcc。 - Santosh A
1
@Iwillnotexist_Idonotexist -- 感谢你的出色挖掘! _asm 已经被弃用,请使用 __asm,但仍然无法正常工作。SDCC帮助文档中提到它是v3.1.0版本。我在编译器选项中没有看到任何内联汇编标志。 - CarpeCimex
1
@Iwillnotexist_Idonotexist -- 做到了!我在手册中找到了preproc_asm的描述。它应该默认为“开启”,但似乎并没有。加上+-也可以工作。请将此放入答案中,我会点赞的。没有你的帮助,我绝对不可能想出这个解决方法! - CarpeCimex
显示剩余3条评论
2个回答

2

评论中移动

SDCC 3.1.0源代码的词法分析器中,我看到同时支持_asm/_endasm__asm/__endasm。我还没有注意到解析器中是否支持__asm("string")

此外,在词法分析器的代码中,只有当一个名为preproc_asm的属性被设置为0时,内联汇编标记“blob”的词法类型才会更改为CPP_ASM,这可以在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
1
在文件顶部加上#pragma preproc_asm +,并像手册第51页顶部那样添加一个多行的__asm ... __endasm汇编块即可。非常感谢! - CarpeCimex
@CarpeCimex 重新考虑一下:代码仅仅是编译通过了还是实际上在二进制输出中存在“nop”? - Iwillnotexist Idonotexist
1
@Iwillnotexist_Idonotexist :-) 我也很担心这个问题,实际上汇编代码出现在汇编清单中。 - CarpeCimex

0

这个链接: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的。你链接到了另一个系统的参考资料。 - John Zwinck
2
为了捍卫回答,据我所知GCC不支持8051,并且问题也是关于8051的。我想说这个人究竟在问什么部分还有点不太清楚。 - Christian Hujer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接