Индексированный переход C / C ++ в набор NOP - PullRequest
0 голосов
/ 25 февраля 2019

Я хочу произвести задержки с разрешением в один такт, поэтому я думаю, что нужно иметь 255 NOP один за другим, а затем перейти к последнему минус требуемая задержка.Таким образом, 0 перепрыгнет через последнюю NOP, 1 - до последней NOP, а 255 - до первой NOP.

Ранее я использовал вызовы индексированных функций, но ничего не могу найти в индексированных gotos, подобных этому.Я также подумал об использовании оператора switch, но в нем, похоже, были другие инструкции.

Любые предложения с благодарностью приняты.

1 Ответ

0 голосов
/ 25 февраля 2019

Ник ODell имеет хорошее решение, но компилятор не может знать, что во всех ваших случаях будет ровно один байт кода.Это не будет известно, пока ассемблер не пройдет.Таким образом, компилятор должен генерировать что-то, что будет работать независимо от того, сколько кода было создано в каждом из ваших случаев, и косвенная таблица переходов - действительно единственный способ сделать это.

Таким образом, я думаю, чтобыполучить «идеальный» код, с одним байтом на nop, вам также придется написать логику перехода в сборке.

Вот что я придумал (для gcc / amd64 / gas в Linux). Вот это на Годболте .

#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, чтобы получить абсолютный программный адрес в регистр.

Конечно, всегда возникает вопрос, являются ли издержки на самом делеполучение этого кода испортит точность вашего времени задержки ...

...