Итак, я пытался изучить MIPS в течение последних нескольких часов, и я столкнулся с проблемой, которая, как мне кажется, связана с моим непониманием того, как MIPS выполняет динамически связанные вызовы (в сочетании с в значительной степени недокументированным псевдосигналом GAS).ops).
Насколько я понимаю, в настоящее время это так: .cpload $t9
просто сообщает ассемблеру, что вы хотите получить адрес глобального указателя (где все инструкции jal
для динамически связанных функций будут по существуjalr $t9
) и .cprestore *offset*
просто говорят ассемблеру хранить значение $gp
в *offset*($sp)
, чтобы оно не перекрывалось при вызовах динамически связанных функций.
Я былИмея хоть какой-то успех в выполнении вызовов функций libc друг за другом, я, в конечном счете, продолжаю сталкиваться с segfaults, которые, я считаю, связаны с какой-то формой сбоев, о которых я не знаю.
Код вВопрос заключается в следующем:
.data
in: .asciz "%d"
out: .asciz "%d\n"
.text
.globl main
main:
.ent main
.frame $sp, 32, $ra
.set noreorder
.cpload $t9
.set reorder
addiu $sp, $sp, -32
sw $ra, ($sp)
.cprestore 4
addiu $a1, $sp, 8
la $a0, in
jal scanf
lw $a1, 8($sp)
la $a0, out
li $v0, 0
jal printf
lw $ra, ($sp)
li $v0, 0
jr $ra
addiu $sp, $sp, 32
.end main
Код не работает после того, как я ввел значение в scanf
.С tty отчётами qemu:
[14517.685107] do_page_fault(): sending SIGSEGV to clz for invalid read access from 00000000
[14517.685474] epc = 00000000 in clz[56255000+1000]
[14517.685680] ra = 56255830 in clz[56255000+1000]
Я полагал, что проблема могла быть вызвана слотами задержки ветвления после инструкций загрузки и перехода, но я смутно читал, что .set reorder
позволяет ассемблеру исправлять ихnop
s (или другие инструкции, которые не влияют на предыдущую инструкцию) неявно.
Итак, я не понимаю, почему это происходит.Я не верю, что это проблема исключительно с printf
, так как я могу назвать это нормально с немедленными запросами, и у меня были подобные проблемы с загрузкой сохраненных в стеке значений перед вызовами других функций libc (таких как free
).
Я был бы очень признателен, если бы кто-то мог обнаружить проблему и / или дать представление о том, как следует выполнять динамические вызовы идиоматическим образом (я могу найти мало информации в Интернете, и objdump
опускает многоподробно - например, символы).
Я хотел бы уточнить:
1) Как часто следует использовать .cprestore
?Означает ли это, что каждый динамический вызов извлекает сохраненное значение (до тех пор, пока конфигурация стека не изменяется)?Если вы расширяете стек, а затем делаете динамический вызов, вам нужно будет использовать .cprestore
, чтобы сообщить ассемблеру, что $gp
находится в другом относительном месте, чем $sp
.
2)быть явным при выполнении инструкций, которые могут быть выполнены со слотами задержки ветвления?(как в: я должен явно писать nop
после определенных инструкций или ассемблер обработает это для меня?)
3) Я читал, что стек MIPS должен быть двойным словом (8 байт)выровнены?Это правда?Я определенно сталкивался с проблемами с другими, выровненными по словам, размерами стека (и даже смещениями хранилища).
Я знаю, что это довольно длинный, запутанный вопрос, который я задал, ноЯ действительно в растерянности.Спасибо за чтение, любая помощь будет высоко ценится.