Вот исходный код для очень простой 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
. Есть идеи, как это работает?