Записать байт по адресу в сегменте.data в сборке RISC-V

Я пишу программу сборки RISC-V, в которой нужно сохранить слово (сохраненное в регистре) в сегменте.data:

.section .rodata
msg:
    .string "Hello World\n"

.section .data
num:
    .word 97 

.section .text
.global _start

_start:

    li a1, 100
    sw a1, num

    loop:
        j loop

Но когда программа достигает sw a1, num Я получаю ошибку "недопустимые операнды`sw a1,num'". Как я могу хранить данные в памяти внутри сегмента.data? не могли бы вы дать мне несколько советов?

1 ответ

Как общее практическое правило, сборка, которую вы пишете на ассемблере, является собственным языком программирования, который, похоже, очень похож на то, что написано в руководстве по RISC-V ISA. RISC-V - довольно простой ISA, поэтому для большинства инструкций фактически нет разницы между синтаксисом руководства ISA и синтаксисом, принятым ассемблером. Место, где это начинает разрушаться, - это ссылка на символы, потому что, хотя вы можете заполнять непосредственное непосредственно в коде сборки, вы, вероятно, захотите сделать так, чтобы компоновщик делал это, потому что вы не будете знать фактический адрес символа до времени ссылки (и это может измениться, как вы измените свою программу).

Чтобы позволить компоновщику заполнять адреса символов в вашем коде, вам нужно передать перемещения из ассемблера, чтобы компоновщик мог позже заполнить их. У меня есть целое сообщение в блоге о том, как это работает в блоге SiFive, но мы просто обновили сайт, и я не могу понять, как его найти:).

В этом случае вы, по сути, пытаетесь написать сборку, которая реализует следующий код C

int num = 97;
void func(int val) { num = val; }

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

func:
    lui t0, %hi(num)
    sw  a0, %lo(num)(a0)
    ret

Вы можете создать эту сборку из моего кода на C выше, скомпилировав -mcmodel=medlow -mexplicit-relocs -O3, Руководство GCC определяет другие специфические опции RISC-V, которые управляют генерацией кода.

Если вас интересует более подробная информация, у нас есть руководство по сборке, доступное на GitHub: https://github.com/riscv/riscv-asm-manual/blob/master/riscv-asm.md. Это далеко не завершено, но мы хотели бы получить помощь, чтобы указать на проблемы или предоставить больше контента.

Синтаксис запасного слова (sw) инструкция

sw rs2, offset(rs1)

где смещение - это 12-битный непосредственный операнд.

Когда ты пишешь sw a1, num вы получаете синтаксическую ошибку, и ассемблер не работает:

foo.s: : Assembler messages:
foo.s::13: Error: illegal operands `sw a1,num'

Возможно, самый простой способ решить эту проблему - использовать адрес загрузки (la) псевдо-инструкция:

li a1, 100
la t0, num
sw a1, 0(t0)

Поскольку la инструкция полностью загружает адрес в регистр, который мы должны использовать 0 как смещение.

В la псевдо-инструкция расширяется до относительной адресации программного счетчика (ПК), т.е. objdump:

00000000000100b0 <_start>:
   100b0:   06400593            addi    a1,zero,100
   100b4:   00001297            auipc   t0,0x1
   100b8:   01028293            addi    t0,t0,16 # 110c4 <__DATA_BEGIN__>
   100bc:   00b2a023            sw  a1,0(t0)

В качестве альтернативы вы можете использовать абсолютную адресацию:

li a1, 100
lui t0, %hi(num)
sw a1, %lo(num)(t0)

Обратите внимание, что %hi() а также %lo() Макросы ассемблера разделяют 32-битный адрес на его старшие 20-битные и младшие 12-битные части (т.е. %hi(num) + sign_ext(%lo(num)) = num).

Другие вопросы по тегам