我想以一个时钟的分辨率产生延迟,因此我的想法是要使255个接头一个接一个地,然后跳到最后一个减去所需的延迟。因此,0将跳过最后一个NOP,1到最后一个NOP,而255到第一个NOP。
我以前使用过索引函数调用,但在类似的索引gotos上找不到任何东西。我还考虑过使用开关语句,但似乎有其他说明。
感激地收到的任何建议。
尼克·奥德尔(Nick Odell)有一个不错的解决方案,但是编译器无法知道您的所有情况都完全具有一个代码字节。直到汇编器通行证才能知道这一点。因此,无论您在每种情况下生产多少代码,编译器都必须产生可以工作的东西,而间接跳台确实是这样做的唯一方法。
因此,我认为为了获得"理想"代码,每个nop一个字节,您也必须在汇编中编写跳跃逻辑。
这是我想到的(对于Linux上的GCC/AMD64/GAS)。在这里,它在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
之类的技巧将绝对程序地址输入寄存器。
当然,总是有一个问题,即实际进入此代码的开销是否会弄乱您的延迟时间的准确性...