Опубликован: 19.01.2025 | Доступ: свободный | Студентов: 1 / 0 | Длительность: 02:34:00
Лекция 5:

Программирование на языке Assembler

< Лекция 4 || Лекция 5: 12345 || Лекция 6 >

Псевдо-инструкции

Компилятор языка Assembler транслирует программу в машинный код. В рамках курса в основном рассматривается GNU assembler. Компилятор понимает не только инструкции RISC-V, определяемые стандартом ISA, но также понимает псевдо-инструкции и псевдо-директивы.

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

Псевдо-инструкции для загрузки, сохранения и дополнения

Таблица 4.2.
Псевдо-инструкция Набор базовых инструкций Описание
la rd, symbol auipc rd, symbol[31:12] addi rd, symbol[11:0] Загрузить адрес (не позиционно-независимый код - non-PIC)
la rd, symbol auipc rd, symbol@GOT[31:12] l{w|d} rd, symbol[11:0](rd) Загрузить адрес (позиционно-независимый код - PIC)
lla ra, symbol auipc rd, symbol[31:12] addi rd, rd, symbol[11:0] Загрузить локальный адрес
lga rd, symbol auipc rd, symbol@GOT[31:12] l{w|d} rd, symbol@GOT[11:0](rd) Загрузить глобальный адрес
l{b|h|w|d} rd, symbol auipc rd, symbol[31:12] l{b|h|w|d} rd, symbol[11:0](rd) Загрузить глобальное значение
s{b|h|w|d} rs, symbol, rd auipc rd, symbol[31:12] s{b|h|w|d} rs, symbol[11:0](rd) Сохранить глобальное значение
nop addi x0, x0, 0 Нет операции
li rd, imm Различные варианты инструкций Загрузить непосредственное значение
mv rd, rs addi rd, rs, 0 Скопировать значение регистра
not rd, rs xori rd, rs, -1 дополнение до 1 (инверсия битов)
neg rd, rs sub rd, x0, rs дополнение до 2 (инверсия битов с добавлением 1)
negw rd, rs subw rd, x0, rs дополнение до 2 (слово)

Положение позиционно-независимого кода (Position Independent Code, PIC) в адресном пространстве зависит только от настроек компоновщика (а не от архитектуры) и полезно для генерации бинарного кода библиотек, которые могут использоваться другими программами. Такой код обычно используется совместно с глобальной таблицей смещений (Global Offset Table, GOT), которая хранится в исполняемом модуле и позволяет операционной системе загружать библиотеки при старте вызывающих программ по различным адресам памяти. Тема, связанная с этим вопросом, является достаточно сложной и не будет рассмотрена в рамках данного курса.

Для самостоятельно изучения вопросов, связанных с форматом ELF, можно посоветовать ознакомиться с документом RISC-V ELF Specification, доступным по адресу https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc.

Отдельно стоит отметить, что псевдо-инструкция lga не поддерживается в наборе инструментов GNU toolchain версии 2.39 и ниже.

Рассмотрим на примере следующего кода, как он транслируется с точки зрения компилятора языка Assembler:

.text
.globl _start
_start:
    la x1, counter    #load address of counter
    addi x1, x1, 4    #go to next word address += 4
    lw x2, 0(x1)      #load value from address, the 2

    li x1, 2
    lw x3, counter    #load word from address counter, the 0
    add x3, x2, x1    #add: x3 = x2 + x1
    sw x3, counter, x2 #save x3, use x2 for address
.data
counter:
    .word 0, 2

Disassembly of section .text:

00000000000100e8 <_start>:
   100e8: 00001097           auipc x1,0x1
   100ec: 02808093           addi x1,x1,40 # 11110 <__DATA_BEGIN__>
   100f0: 00408093           addi x1,x1,4
   100f4: 0000a103           lw x2,0(x1)
   100f8: 00200093           addi x1,x0,2
   100fc: 00001197           auipc x3,0x1
   10100: 0141a183           lw x3,20(x3) # 11110 <__DATA_BEGIN__>
   10104: 001101b3           add x3,x2,x1
   10108: 00001117           auipc x2,0x1
   1010c: 00312423           sw x3,8(x2) # 11110 <__DATA_BEGIN__>

Адрес метки counter в памяти равен 0b11110. Псевдо-инструкции транслируются в базовые инструкции следующим образом:

la x1, counter               -> auipc x1,0x1; addi x1, x1, 40
li x1, 2                     -> addi x1, x0, 2
lw x3, counter               -> auipc x3, 0x1; lw x3, 20(x3)
sw x3, counter, x2           -> auipc x2, 0x1; sw x3, 8(x2)

Псевдо-инструкции для условной установки битов

Таблица 4.3 ниже показывает псевдо-инструкции и базовые инструкции для расширения и условной установки битов:

Таблица 4.3.
Псевдо-инструкция Набор базовых инструкций Описание
sext.{b|h|w} rd, rs Может быть различный набор инструкций sign extend
zext.{b|h|w} rd, rs Может быть различный набор инструкций zero extend
seqz rd, rs sltiu rd, rs, 1 rd = (rs == 0)? 1:0
snez rd, rs sltu rd, x0, rs rd = (rs != 0)? 1:0
sltz rd, rs slt rd, rs, x0 rd = (rs < 0)? 1:0
sgtz rd, rs slt rd, x0, rs rd = (rs > 0)? 1:0
< Лекция 4 || Лекция 5: 12345 || Лекция 6 >