【问题标题】:C/C++ indexed jump into a set of NOPsC/C++ 索引跳转到一组 NOP
【发布时间】:2019-02-24 22:51:32
【问题描述】:

我想产生一个时钟分辨率的延迟,所以我的想法是一个接一个地有 255 个 NOP,然后跳到最后一个减去所需的延迟。所以 0 会跳过最后一个 NOP,1 会跳过最后一个 NOP,255 会跳过第一个 NOP。

我以前使用过索引函数调用,但在索引 goto 上找不到任何像这样的东西。我也想过使用 switch 语句,但似乎还有其他指令。

任何建议都非常感谢。

【问题讨论】:

  • 您查看过您的 switch 语句版本生成的代码吗?
  • 否 - 但它似乎索引了大约三个时钟节拍而不是一个,所以大概还有一些其他指令正在输出。我去看看
  • 对 Godbolt 的快速尝试似乎产生了您正在寻找的东西:godbolt.org/z/146A5A
  • 终于得到了在 AVR-Studio 上工作的汇编输出,它产生了一个指向 NOP 的 rjmp 向量表。所以每个额外的 NOP 有效地占用 4 个字节而不是 1 个字节。我期望代码是直接索引跳转到 NOP,而不是通过间接跳转表。代码是 switch(100-Batt_Percent) { case 100:__asm__ volatile__("nop");案例 99:__asm volatile__("nop"); .... 案例 1:__asm __volatile__("nop");

标签: c delay indexed nop


【解决方案1】:

Nick ODell 有一个很好的解决方案,但编译器无法知道您的所有案例都只有一个字节的代码。在汇编程序通过之前,这将是未知的。因此,无论在每种情况下生成多少代码,编译器都必须生成可以工作的东西,而间接跳转表确实是唯一的方法。

因此,我认为为了获得每个 nop 一个字节的“理想”代码,您还必须在汇编中编写跳转逻辑。

这是我想出的(用于 Linux 上的 gcc / amd64 / gas)。 Here it is on godbolt.

#include <stdlib.h>

#define N 1000

#define xstr(s) str(s)
#define str(s) #s


void delay(unsigned ticks) {
  if (ticks <= N) {
    asm("movq $1f, %%rax \n"
    "addq %0, %%rax \n"
    "jmp *%%rax \n"
    "1: \n"
    ".rept " xstr(N) " \n"
    "nop \n"
    ".endr \n"
    : : "g" ((unsigned long)(N-ticks)): "ax");
  } else {
    abort();
  }
}

int main(void) {
  delay(4);
  return 0;
}

注意,它必须用-no-pie 编译。如果您希望它作为与位置无关的可执行文件工作,您可能需要像call 2f ; 2f: popq %rax 这样的技巧将绝对程序地址放入寄存器。

当然,实际获取此代码的开销是否会影响延迟时间的准确性总是存在问题...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-02
    • 2023-03-15
    • 1970-01-01
    • 2021-12-09
    • 2015-11-08
    相关资源
    最近更新 更多