【问题标题】:gnu gcc asm; using "C" enum valuesgnu gcc asm;使用“C”枚举值
【发布时间】:2017-03-21 23:29:00
【问题描述】:

有没有办法从“C”enum 中提取一个值以将它们传递到 gnu gcc asm('.S' 文件)中,而无需某种外部解析器?

我想得到的是

“my_header.h”

enum myErrors
{
    NoError = 0,
    TimeOut = 1,
    BadArgument = 30,
};

“asm_file.S”

mov r0, #myErrors.TimeOut


PS:目前我看到的唯一解决方案是解析“my_header.h”并创建一个包含#define 的辅助文件以包含在“asm_file.S”中。 也许这个问题有一个很好的解决方案。

谢谢。

【问题讨论】:

  • 枚举定义后缺少分号。
  • 你为什么首先从事装配工作?我能想到的唯一合理的原因是手动优化一些速度关键部分。在这种情况下,程序集应该只执行速度关键的工作,并将错误处理留给 C 代码。这消除了从 asm 访问您的枚举的需要。
  • @Unimportant,因为它正是“速度关键部分”,它可能会失败并且必须返回错误

标签: c gcc assembly enums header-files


【解决方案1】:

如果你可以修改头文件,你可以编写一些宏,这样当包含在 C 代码中时,它会吐出 enum,而当在 asm 中时,会吐出一堆 .equ

例子:

#ifdef ASM
#define ENUM(x) .macro item name value ; .equ x##.\name, \value ; .endm
#define ITEM(x, y) item x, y
#define END_ENUM .purgem item
#else 
#define ENUM(x) enum x {
#define ITEM(x, y) x = y,
#define END_ENUM }
#endif

ENUM(myErrors)
ITEM(NoError, 0)
ITEM(TimeOut, 1)
ITEM(BadArgument, 30)
END_ENUM

显然您需要为此进行预处理的程序集(例如.S 文件和gcc 驱动程序)。此外,您的构建系统将需要定义 ASM(或找到适当的预定义宏来检测语言)。

【讨论】:

  • 抱歉,这是不可接受的。我不会被允许推动这种“枚举”的丑陋。
  • 我喜欢你的回答,因为它表明有一种方法可以生成枚举,它在汇编程序和 C 中都很有用。(假设 C 预处理器(如果可用)。 OP 没有任何限制,只是它不是外部解析器。在我看来,这符合要求。
【解决方案2】:

在 C++ 中,您可以这样做:

enum myErrors
{
    NoError = 0,
    TimeOut = 1,
    BadArgument = 30
};

constexpr myErrors no_error = NoError,
                   time_out = TimeOut,
                   bad_argument = BadArgument;

static myErrors last_error = no_error;

myErrors get_last_error()
{
  return last_error;
}

在 Linux x86_64 上使用 g++ 6.2.0 编译,没有优化标志,生成以下程序集:

_Z14get_last_errorv:
.LFB0:
    .file 1 "sx-myerror.cpp"
    .loc 1 15 0
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    .loc 1 16 0
    movl    _ZL10last_error(%rip), %eax
    .loc 1 17 0
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

movl _ZL10last_error(%rip), %eax 行与您想要的很接近。如果您进行优化,它会将该符号常量替换为文字 0。

在 C 中,你可以做的是:

typedef enum myErrors
{
    NoError = 0,
    TimeOut = 1,
    BadArgument = 30
} myErrors;

const myErrors no_error = NoError,
               time_out = TimeOut,
               bad_argument = BadArgument;

myErrors get_last_error()
{
  return no_error;
}

这不太灵活:您不能在静态初始化器中使用const 对象,编译器会将它们优化为常量。但是,它确实会在目标代码中为您提供符号常量名称。

【讨论】:

  • 所以我应该为每个枚举值创建一个包装函数并调用适当的函数。我猜对了吗?
  • 不,包装函数只是对符号常量使用的演示。我包含它是为了验证 gcc -c 将产生的函数体类型。
  • 好的。我想我得到了你。每个枚举值都有一堆常量。并且函数应该在返回之前将常量的值读入寄存器。对?删除名称修改可能会更容易一些:myErrors myNoError asm("asm_no_error") = NoError;。缺点是很多额外的手动声明的常量(我有大约 50 个错误代码)和速度关键代码中的额外指令。这意味着应将一条mov r0, #error_code 指令替换为 3(2 条指令加载常量地址 + 1 条内存读取以读取值)。
  • 该函数只是在此上下文中使用其中一个常量的一个最小示例。我包含它是为了显示一些说明,而不仅仅是一堆变量声明。
猜你喜欢
  • 2011-02-04
  • 1970-01-01
  • 2016-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-05
  • 1970-01-01
相关资源
最近更新 更多