Вызов fgets в сборке RISC-V на Spike / PK

Обновление. Написав это, я понял, в чем я ошибался, но не почему. Я, очевидно, неправильно вызываю fgets, потому что после пяти вызовов я попадаю на адрес 0x221000, где находится память mmapped - я пишу по более высоким адресам - но я не знаю, почему это происходит. Может кто-нибудь объяснить?

Это немного сложно, и я не понимаю, почему наблюдается такое поведение: я не знаю, правильно ли я понял основы или это особенность Spike / PK.

Обратите внимание: libc здесь предоставляется newlib, а код скомпилирован как riscv64-unknown-elf.

Краткая версия. У меня есть входной код, написанный на сборке RISC-V, который раньше работал без сбоев, но, поскольку я ввел системный вызов mmap, он вылетает при пятом выполнении. Проблема в том, что у меня неправильная последовательность вызовов или, возможно, проблема с эмулятором Spike и прокси-ядром PK?

Длинное объяснение

Я пишу Forth-подобный язык с многопоточной интерпретацией. В настоящее время он нацелен на прокси-ядро PK на эмуляторе Spike, но, надеюсь, скоро будет запущен на «реальном» оборудовании. Код находится по адресу https://github.com/mcmenaminadrian/riscyforth.

TIL реализует бесконечный цикл для получения вызова ввода, последовательно, подпрограмму для получения указателя файла для стандартного ввода, а затем процедура для получения ввода.

Чтобы получить стандартный входной указатель файла (который хранится в стеке):

mv a0, zero
la a1, stdinopen
call fdopen
addi sp, sp, -8
sw a0 0(sp)

(stdinopen находится в разделе .data как .asciz r)

Затем, чтобы получить ввод - вытащите его из стека ...

lw a2, 0(sp)
addi sp, sp, 8
la a0, INPUT_BUFFER
li a1, BUFFERLEN #0x200
call fgets

INPUT_BUFFER определен в разделе .bss как .common INPUT_BUFFER, BUFFERLEN, 8

Все это работало нормально, пока я не добавил новый код, отображаемый в некоторой памяти как R / W / X - если вы знаете о Forth, вы будете знать, что мне нужна память с этим необычным набором разрешений, потому что я должен разрешить пользователям определять новые ключевые слова.

Теперь попытка получить ввод не удалась при четвертом вызове. (Хотя, если я определю mmap, проблема исчезнет.)

Вот пример неудачи:





ДОБРО ПОЖАЛОВАТЬ В RISCYFORTH - Авторские права Адриан Макменамин, 2020-2021 гг.


RISCYFORTH - это язык с многопоточной интерпретацией, во многом основанный на FORTH. В настоящее время мы работаем в режиме EXECUTE, и все, что вы вводите, будет выполняться при вводе каждой строки. RISCYFORTH находится под лицензией версии 2 Стандартной общественной лицензии GNU. См. https://github.com/mcmenaminadrian/riscyforth.git.



346 5622 * дубль ОК

дуп хорошо

дуп хорошо

. 1945212 OK

г 0000000000000000 ра 0000000000010442 зр 0000003ffffffaf8 зм 000000000001fe30 ф 0000000000000000 t0 000000000009fa60 t1 000000000000000a t2 0000000000000003 s0 0000000000000000 s1 0000000000000000 a0 000000000001e530 a1 000000000009fa60 a2 0000000000000200 a3 0000000000000000 a4 0000000000221000 a5 0000000000000001 a6 000000000001ec88 a7 00000000000000d6 s2 00000000000001ff s3 000000000009fa60 s4 000000000001e530 s5 000000000009fa60 s6 0000000000000000 s7 0000000000011b64 s8 0000000000010400 s9 000000000011fc58 sA 000000000009f950 sB 0000000000000000 t3 0000000000000064 t4 0000003ffffffb08 t5 0000000000000054 t6 0000000000000054 pc 0000000000011ca4 va / inst 0000000000000008 sr 8000000200006020 Пользовательская загрузка segfault @ 0x0000000000000008

И вот где код не работает:

0000000000011c64 <_fgets_r>:
11c64:       4785                    li      a5,1
11c66:       0ac7de63                bge     a5,a2,11d22 <_fgets_r+0xbe>
11c6a:       7139                    addi    sp,sp,-64
11c6c:       f822                    sd      s0,48(sp)
11c6e:       f04a                    sd      s2,32(sp)
11c70:       ec4e                    sd      s3,24(sp)
11c72:       e852                    sd      s4,16(sp)
11c74:       fc06                    sd      ra,56(sp)
11c76:       f426                    sd      s1,40(sp)
11c78:       e456                    sd      s5,8(sp)
11c7a:       e05a                    sd      s6,0(sp)
11c7c:       8932                    mv      s2,a2
11c7e:       8a2a                    mv      s4,a0
11c80:       89ae                    mv      s3,a1
11c82:       8436                    mv      s0,a3
11c84:       c119                    beqz    a0,11c8a <_fgets_r+0x26>
11c86:       493c                    lw      a5,80(a0)
11c88:       cbc1                    beqz    a5,11d18 <_fgets_r+0xb4>
11c8a:       397d                    addiw   s2,s2,-1
11c8c:       8ace                    mv      s5,s3
11c8e:       a819                    j       11ca4 <_fgets_r+0x40>
11c90:       601c                    ld      a5,0(s0)
11c92:       9f05                    subw    a4,a4,s1
11c94:       9aa6                    add     s5,s5,s1
11c96:       94be                    add     s1,s1,a5
11c98:       c418                    sw      a4,8(s0)
11c9a:       e004                    sd      s1,0(s0)
11c9c:       3cb000ef                jal     ra,12866 <memcpy>
11ca0:       04090f63                beqz    s2,11cfe <_fgets_r+0x9a>
11ca4:       441c                    lw      a5,8(s0)

(_fgets_r вызывается fgets)

0000000000011d26 <fgets>:
11d26:       87aa                    mv      a5,a0
11d28:       8401b503                ld      a0,-1984(gp) # 1f670 <_impure_ptr>
11d2c:       86b2                    mv      a3,a2
11d2e:       862e                    mv      a2,a1
11d30:       85be                    mv      a1,a5
11d32:       bf0d                    j       11c64 <_fgets_r>

Что-то идет не так в memcpy, в результате чего у меня остается эквивалент нулевого указателя, но я не понимаю, что именно, но мой более фундаментальный вопрос таков: Есть ли у меня базовая процедура для правильного вызова fgets?

Я полагаю, что у меня была и не было никаких предыдущих проблем, но документации по этому немного, и поэтому подтверждение было бы полезным и, по крайней мере, предлагало бы мне более внимательно изучить код mmap.

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


person adrianmcmenamin    schedule 18.04.2021    source источник
comment
Если это 64-разрядная версия, вы должны использовать sd для возвращаемого значения из fdopen, нет?   -  person Erik Eidt    schedule 18.04.2021
comment
Наверное! Но проблема не в этом. Я действительно должен скомпилировать это как 32-битное, вы правы.   -  person adrianmcmenamin    schedule 18.04.2021


Ответы (1)


Многократно открывая файл, мой код поглощал все больше и больше памяти и в конечном итоге перезаписывал часть диапазона памяти, выделенного через mmap. Я решил это, сохранив значение указателя файла в .bss (inputfileptr) и открыв его только один раз:

            la t0, inputfileptr
            lw a0, 0(t0)
            bne a0, zero, getstdin_getin
            la a1, stdinopen
            call fdopen                
            la t0, inputfileptr
            sw a0, 0(t0)
            getstdin_getin:
            PUSH a0                          #store value on stack
person adrianmcmenamin    schedule 19.04.2021