Как этот сгенерированный gcc цикл strlen () mips не отключается? - PullRequest
1 голос
/ 11 марта 2019

Вот исходный код для очень простой strlen() реализации.

#include <stddef.h>
#include <stdint.h>

extern uintptr_t lx_syscall3(uintptr_t a, uintptr_t b, uintptr_t c, uintptr_t nr);

static void lx_sys_exit(uintptr_t code)
{
  lx_syscall3(code, 0, 0, 4001);
  while (1);
}

static size_t lx_strlen(char const* s)
{
  size_t len = 0;

  while (*(s++)) {
    len++;
  }

  return len;
}

int main() {
  lx_sys_exit(lx_strlen("HELO"));
  while (1);
}

Скомпилированный вместе с файлом syscall.s, не относящимся к этому вопросу, сгенерированный код GCC для lx_strlen встраивается в main (при -Os):

004004fc <main>:
  4004fc: 3c1c000b  lui gp,0xb
  400500: 279c8154  addiu gp,gp,-32428
  400504: 0399e021  addu gp,gp,t9
  400508: 8f828034  lw v0,-32716(gp)
  40050c: 27bdffe0  addiu sp,sp,-32
  400510: 24424a64  addiu v0,v0,19044
  400514: afbc0010  sw gp,16(sp)
  400518: afbf001c  sw ra,28(sp)
  40051c: 00402825  move a1,v0
  400520: 00452023  subu a0,v0,a1

  # strlen loop block follows
  400524: 24420001  addiu v0,v0,1
  400528: 8043ffff  lb v1,-1(v0)
  40052c: 5460fffd  bnezl v1,400524 <main+0x28>
  400530: 00452023  subu a0,v0,a1

  400534: 8f998118  lw t9,-32488(gp)
  400538: 24070fa1  li a3,4001
  40053c: 00003025  move a2,zero
  400540: 04110093  bal 400790 <lx_syscall3>
  400544: 00002825  move a1,zero
  400548: 1000ffff  b 400548 <main+0x4c>
  40054c: 00000000  nop

При запуске с qemu-mipsel код правильно выводит состояние выхода 4. Так что, похоже, все в порядке, проблема в том, что я просто не понимаю , как это может работать. Обратите внимание на смещение -1(v0) на 400528. Таким образом, цикл всегда проверяет предыдущий байт с адреса, хранящегося в v0. Таким образом, к нулевому времени вычитание исходного адреса должно дать 5, а не 4. Есть идеи, как это работает?

1 Ответ

1 голос
/ 11 марта 2019

Код использует инструкцию bnezl, которая имеет специальную обработку инструкции слота задержки: она выполняется только в том случае, если берется ветвление. Следовательно, ваш код всегда будет использовать $a0 из предыдущей итерации, потому что subu a0,v0,a1 в 400530 не выполняется для последней, которая выходит из цикла. Обратите внимание, что на 400520 $a0 обнуляется для случая строки нулевой длины.

...