Ассемблер для Power-архитектуры, Часть 2: Искусство загрузки и сохранения на PowerPC

Техника загрузки данных именно туда, куда вам нужно.

Предыдущая статья этой серии представляла программирование на ассемблере с использованием набора команд 64-битного PowerPC® на POWER5 и других процессорах, использующих эти команды. В этой статье будет обсуждена специфика программирования на ассемблере для 64-битного PowerPC на Linux® и UNIX®-подобных системах, причем основное внимание обращается на методы доступа к данным и на создание перемещаемого кода.

Джонатан Бартлетт, технический директор, New Media Worx

Джонатан Бартлет (Jonathan Bartlett) является автором книги "Программирование с нуля" - введения в программирование на языке ассемблера для Linux. Он является ведущим разработчиком в New Media Worx и занимается Web-приложениями (видео, киосками), а также настольными приложениями для клиентов. Вы можете связаться с ним по адресу johnnyb@eskimo.com.



24.04.2007

Режимы адресации, и почему они важны

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

  • Каждая ячейка основной памяти нумеруется последовательным числовым адресом, по которому эта ячейка может быть найдена.
  • Каждая ячейка в основной памяти имеет длину один байт.
  • Более длинные типы данных получаются интерпретированием нескольких байтов как единого объекта (например, для 16-битного числа используют вместе две ячейки памяти).
  • Регистры имеют длину 4 байта для 32-битной платформы и 8 байтов для 64-битной.
  • Данные из памяти могут загружаться в регистры по 1,2,4 или 8 байтам за раз.
  • Нечисловые данные хранятся как числа, единственная разница состоит в том, какие операции можно использовать на этих данных и как эти данные используются.

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

Как ни странно, есть два режима адресации, которые вообще не имеют доступа к памяти. В immediate mode используемые данные являются частью команды (например, команда li обозначает "load immediate", поскольку загружаемое число является частью самой команды). В register mode вместо доступа к содержимому памяти вы обращаетесь к регистрам.

Наиболее наглядный режим адресации основной памяти называется direct addressing mode. В этом режиме сама команда содержит адрес памяти, из которого нужно загрузить данные. Этот режим часто используется для доступа к глобальным переменным, для ветвлений и вызова подпрограмм. Похожий режим -- relative addressing mode, который вычисляет адрес, основываясь на текущем значении счетчика команд. Он часто используется для "коротких" ветвлений, где осуществляется переход к команде, находящейся в непосредственной близости от текущей команды, поэтому имеет больше смысла задавать смещение вместо абсолютного адреса. Этот режим похож на direct addressing mode, где конечный адрес известен в процессе ассемблирования или в процессе компоновки.

Indexed addressing mode наиболее удобен при доступе к элементам массивов глобальных переменных. Он имеет две составные части: адрес в памяти и индекс-регистр. Индекс-регистр прибавляется к указанному адресу, и полученное значение используется для доступа к памяти. Некоторые платформы (не PowerPC) позволяют указывать множитель для индекс-регистра. Поэтому, если каждый элемент массива имеет длину 8 байт, можно использовать множитель 8. Это позволяет индекс-регистру быть в точности индексом массива. Иначе индекс-регистр должен был бы уменьшаться/увеличиваться с приращением, равным размеру элемента данных.

Register indirect addressing mode использует регистр для указания полного адреса для доступа к памяти. Этот режим используется в ряде ситуаций, включающих следующие (но не ограничивающиеся ими):

  • Получение значения по указателю переменной
  • Любой доступ к памяти, не доступный в других режимах (адрес может быть рассчитан другими методами и сохранен в регистре, который в последствии будет использован для доступа к памяти)

Base-pointer addressing mode работает похоже на indexed addressing mode (для получения результирующего адреса указанное число и регистр складываются) , за исключением того, что параметры меняются значениями. В base-pointer addressing mode регистр содержит базовый адрес, а число содержит смещение. Это очень удобно для доступа к элементам структур. Регистр может содержать адрес всей структуры, а числовое значение может изменяться в зависимости от того, к какому элементу структуры мы обращаемся.

Например, предположим, у вас есть структура, у которой есть три поля: первое - 8 байтов, второе - 4 байта и последнее - 8 байтов. Пусть адрес самой структуры хранится в регистре X, тогда, если вы хотите получить доступ ко второму элементу структуры, вам необходимо добавить 8 к значению в регистре. Поэтому, используя base-pointer addressing, вы указываете регистр X как базовый адрес и 8 как смещение. Для доступа к третьему полю вы должны указать регистр X, как базовый адрес и 12 в качестве смещения. Для доступа к первому полю, поскольку смещения нет, вы можете использовать indirect addressing вместо base-pointer addressing (поэтому на многих платформах доступ к первому элементу структуры самый быстрый -- однако для PowerPC это не имеет значения).

И наконец, в indexed register indirect addressing mode оба, и базовый адрес, и индекс, хранятся в регистрах. Адрес ячейки памяти вычисляется сложением двух регистров.

Важность структуры команд

Для того чтобы понять, как работают на процессорах PowerPC режимы адресации для команд сохранения и загрузки, сначала вы должны немного разобраться в структуре команд PowerPC. PowerPC имеет load/store архитектуру (также известную как RISC), это означает, что доступ к оперативной памяти осуществляется только для загрузки в регистры или для копирования регистров в память. А все операции выполняются между регистрами (или между регистрами и непосредственными операндами). Другая основная процессорная архитектура - CISC (x86 процессор является популярным представителем CISC архитектуры), позволяет обращаться к памяти практически в любой команде. Основной причиной для использования load/store архитектуры является тот факт, что она позволяет процессору работать более эффективно. Фактически, наиболее современные CISC процессоры для эффективности переводят свои команды во внутренний RISC формат.

Каждая команда в PowerPC длиной ровно 32 бита, вместе с кодом операции команды (который говорит процессору, что это за команда), занимающим первые 6 бит. Эти 32 бита включают в себя непосредственные операнды, ссылки на регистры и параметры команды. Фактически, максимальная длина, доступная для адресации памяти в любом формате команды, всего 24 бита! Это дает вам максимум 16Мб адресного пространства. Не беспокойтесь -- есть много способов обойти это ограничение. Этот пример был приведен для того, чтобы обратить внимание, почему формат команды важен для PowerPC процессора, вы должны знать, как много у вас места, с которым вы можете работать!

Вам не нужно запоминать все форматы команд, чтобы использовать их. Однако знание некоторых базовых форматов поможет вам читать документацию по PowerPC, а так же понимать основные методики и нюансы в архитектуре PowerPC. PowerPC имеет 15 различных форматов команд, многие с несколькими подформатами. Однако вам нужно обратить внимание только на несколько из них.


Адресация памяти с использованием команд формата D-Form и DS-Form

D-Form -- один из основных форматов команд для доступа к памяти. Он выглядит следующим образом:

Формат команд D-Form

Биты 0-5

код операции

Биты 6-10

Входящий/исходящий регистр

Биты 11-16

Адрес/индекс-регистр/операнд

Биты 16-31

Числовой адрес, смещение или непосредственные значения

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

  • Immediate addressing mode
  • Direct addressing mode (указывая ноль для адрес/индекс регистра)
  • Indexed addressing mode
  • Indirect addressing mode (указывая 0 для адреса)
  • Base pointer addressing mode

Как вы можете видеть, команды формата D-Form очень гибкие и используются для любого регистр-плюс-адрес типа доступа к памяти. Однако удобство их использования для direct addressing и indexed addressing чрезвычайно ограничено из-за того, что они имеют всего 16-битное поле для работы с адресом! Это дает максимальный диапазон 64К. Поэтому direct и indexed режимы адресации редко используются для считывания из памяти и сохранения в нее. Зато этот формат существенно чаще используется для indirect и base-pointer режимов адресации, поскольку в этих режимах адресации ограничение в 64К едва ли является проблематичным, так как базовый регистр может иметь полный 64-битный диапазон.

Формат DS-Form используется только в 64-битных командах. Он похож на D-Form, за исключением того, что использует последние два бита для расширенного кода операции. Однако он дополняет двумя нулями справа значимую часть адреса. Это дает такой же диапазон, как и в командах D-Form (64К), но ограничивает его памятью, распределенной по 32 бита. В ассемблере значения указываются как обычно -- они просто преобразуются ассемблером. Например, если вам нужно смещение 8, вы и должны вводить 8, ассемблер преобразует значение в битовое представление 0b000000000010 вместо 0b00000000001000. Если вы введете значение, которое не делится на 4, ассемблер выдаст ошибку.

Отметим, что в D-Form и DS-Form командах, если исходный регистр установлен равным нулю, вместо использования регистра 0 они просто не используют регистр.

Посмотрим теперь на команды, созданные на основе D-Forms and DS-Forms.

Команды непосредственного режима (immediate-mode) задаются в ассемблере следующим образом:

opcode dst, src, value

Здесь dst -- регистр назначения, src -- исходный регистр (используемый в вычислениях), и value -- используемая в непосредственном режиме величина. Команды непосредственного режима никогда не используют DS-Form. Ниже приведены некоторые команды непосредственного режима:

Листинг 1. Команды непосредственного режима
#Сложить содержимое регистра 3 с числом 25 и сохранить в регистре 2
addi 2, 3, 25

#Выполнить логическое ИЛИ содержимого регистра 6 с числом 0b0000000000000001 и 
#сохранить в регистре 3
ori 3, 6, 0b00000000000001

# Поместить число 55 в регистр 7
#(помните, когда во втором регистре D-form команды указан 0,
# это означает не учитывать  регистр)
addi 7, 0, 55
#Ниже, эта же команда в расширенной символике
li 7, 55

При использовании D-Form в других режимах (кроме непосредственного) второй регистр складывается со значением для получения конечного адреса, в который будут сохранены или из которого загружены данные. Эти команды имеют следующий вид:

opcode dst, d(a)

Здесь адрес для записи/чтения указывается как d(a), где d числовой адрес/смещение и a номер регистра, используемого как адрес/смещение. Они складываются вместе для получения эффективного адреса для чтения/записи. Ниже несколько примеров D-Form/DS-Form команд для чтения/записи:

Листинг 2. Примеры команд чтения/записи использующих D-Form и DS-Form
#загрузить байт из адреса находящегося в регистре 2, сохранить его в регистре 3
#и обнулить оставшиеся биты
lbz 3, 0(2)

#сохранить 64-битное содержимое регистра 5 (двойное слово) в ячейке памяти с
#адресом, который расположен на 32 бита после адреса, указанного в регистре 23
std 5, 32(23)

#сохранить низшие 32-бита (слово) регистра 5 в ячейке памяти с
#адресом, который расположен на 32 бита после адреса, указанного в регистре 23
stw 5, 32(23)

#сохранить низшие 8 бит регистра 30 в ячейке памяти с
#адресом, указанным в регистре 4
stb 30, 0(4)

#загрузить 16 бит (полуслово) из ячейки памяти с адресом 300 в регистр 4 
#и обнулить оставшиеся биты
lhz 4, 300(0)

#загрузить полуслово (16 бит) из адреса, смещенного на один байт от адреса
#в регистре  31, и сохранить значение, дополненное знаком в регистр 18
lha 18, 1(31)

Посмотрев повнимательнее, вы заметите, что в начале команды указано нечто вроде "базового кода операции", за которым следуют несколько модификаторов. l и s используются для обозначения "load" и "store." b обозначает байт, h обозначает полуслово (halfword) (16 бит), w обозначает слово (word) (32 бита) и d обозначает двойное слово (doubleword) (64 бита). После этого для load модификаторы a и z сообщают, является ли величина величиной со знаком или же она просто дополняется нулями при загрузке в регистр. И, наконец, модификатор u может быть добавлен для того, чтобы сообщить процессору о необходимости обновить регистр, использованный для вычисления адреса, и поместить туда конечный адрес вычисленной команды.


Адресация с использованием формата команд X-Form

X-Form используется для индексируемой косвенной адресации. В X-Form значения двух регистров складываются для определения адреса загрузки/сохранения. X-Form имеет следующий формат:

Формат команд X-Form

Биты 0-5

Код операции

Биты 6-10

Регистр назначения / исходный регистр

Биты 11-15

Регистр A для вычисления адреса

Биты 16-20

Регистр B для вычисления адреса

Биты 21-30

Расширенный код операции

Бит 31

Не используется

Команды имеют следующий формат:

opcode dst, rega, regb

Здесь opcode -- код операции команды, dst -- регистр назначения (или источник) для передачи данных, а rega и regb -- два регистра, используемые для вычисления адреса.

Ниже примеры команд, использующих X-Form:

Листинг 3. Примеры, использующие X-Form адресацию
#Загрузить двойное слово (64 бита) из адреса, получаемого сложением 
#регистра 3 и регистра 20, и сохранить значение в регистре 31 
ldx 31, 3, 20

#Загрузить байт из адреса, получаемого сложением регистров 10 и 12,
#сохранить в регистре 15 и установить в 0 остальные биты
lbzx 15, 10, 12

#Загрузить полуслово (16 бит)  из адреса, получаемого сложением 
#регистров 6 и 7, и сохранить значение, дополненное знаком в регистре 8. 
lhax 8, 6, 7

#Взять двойное слово (64 бита) из регистра 20 и сохранить его 
#по адресу, получаемому сложением регистров 10 и 11. 
stdx 20, 10, 11

#Взять двойное слово (64 бита) из регистра 20 и сохранить его
#по адресу, получаемому сложением регистров 10 и 11, и затем поместить
#в регистр 10 вычисленный адрес 
stdux 20, 10, 11

Кроме того, что X-Form очень гибкая, ее преимущества состоит в том, что в X-Form вы имеете существенно более широкий диапазон адресов. В D-Form только одна величина – регистр – может указывать на весь диапазон. Тогда как в X-Form вы имеете два регистра, и оба компонента могут указывать диапазон такой длины, которая необходима. Поэтому в ситуациях, когда должна использоваться base-pointer или indexed адресация, но 16-битный диапазон постоянной части в D-Form слишком мал, эта величина может быть сохранена в регистре и использоваться в X-Form.


Создание позиционно-независимого кода

Позиционно-независимый код – это код, который работает независимо от того, в какую часть памяти он загружен. Зачем нужен позиционно-независимый код? Позиционно-независимый код позволяет загружать библиотеки в произвольное место в адресном пространстве. Это позволяет произвольно комбинировать библиотеки: так как ни у одной из них нет особых областей памяти, к которым они привязаны, библиотеки могут быть загружены вместе с любыми другими библиотеками, не беспокоясь о конфликтах в пространстве адресов. Компоновщик заботится о том, чтобы быть уверенным, что каждая библиотека загружена в свое собственное пространство. Благодаря использованию перемещаемого кода, библиотекам не нужно волноваться о том, куда они загружены.

Однако, в конечном счете, позиционно-независимый код требует метода локализации глобальных переменных. Это осуществляется при помощи глобальной таблицы смещений (global offset table), которая обеспечивает адреса для всей глобальной информации, к которой функция или группа функций должна иметь доступ (или даже, в большинстве случаев, вся программа). Резервируется регистр для хранения указателя к таблице. И весь доступ осуществляются путем смещений в таблице. Смещения постоянны. Сама таблица настраивается компоновщиком/загрузчиком программы, который также инициализирует регистр 2 для хранения указателя на глобальную таблицу смещений. Используя этот метод, компоновщик/загрузчик может размещать как программу, так и данные туда, куда он считает подходящим, и ему необходимо только настроить глобальную таблицу смещений, содержащую все глобальные указатели.

Легко увязнуть в дискуссии обо всем этом. Давайте посмотрим на некоторые коды и проанализируем, что происходит на каждом шаге. Это программа "сложения чисел", использовавшаяся в предыдущей статье, но адаптированная под позиционно-независимый код.

Листинг 4. Доступ к данным при помощи глобальной таблицы смещений
###ОПИСАНИЕ ДАННЫХ###
.data
.align 3
first_value:
        .quad 1
second_value:
        .quad 2

###ОПИСАНИЕ ТОЧКИ ВХОДА###
.section .opd, "aw"
.align 3
.globl _start
_start:
        .quad ._start, .TOC.@tocbase, 0

###КОД###
.text
._start:
        ##Загрузка значений##
        #Загрузить адрес величины first_value в регистр 7 
	#из глобальной таблицы смещений (global offset table)
        ld 7, first_value@got(2)
        #Использовать адрес для загрузки значения first_value в регистр 4
        ld 4, 0(7)
        #Загрузить адрес величины second_value  в регистр 7 из глобальной таблицы смещений
        ld 7, second_value@got(2)
	#Использовать адрес для загрузки значения second_value в регистр 5
        ld 5, 0(7)

        ##Выполнить сложение##
        add 3, 4, 5

        ##Выйти с кодом возврата##
        li 0, 1
        sc

Для ассемблирования, компоновки и запуска кода выполните следующее:

Листинг 5. Ассемблирование, компоновка и запуск кода
#Ассемблирование
as -a64 addnumbers.s -o addnumbers.o

#Компоновка
ld -melf64ppc addnumbers.o -o addnumbers

#Запуск
./addnumbers

#Просмотр код возврата (значение, возвращаемое программой)
echo $?

Описание данных и точки входа точно такие же, как и прежде. Однако теперь вместо того, чтобы использовать 5 команд для загрузки адреса first_value в регистр 7, нужна только одна команда: ld 7, first_value@got(2). Как я отмечал ранее, компоновщик/загрузчик устанавливает регистр 2 равным адресу глобальной таблицы смещений. Синтаксис first_value@got просит компоновщик использовать вместо адреса первой величины first_value смещение внутри глобальной таблицы смещений, которая содержит адрес first_value.

Используя этот метод, большинство программ может содержать все глобальные данные, которые они используют, внутри одной глобальной таблицы смещений. DS-Form может адресовать до 64К памяти от одного базового адреса. Заметьте, что, чтобы получить полный диапазон DS-Form, регистр 2 указывает на середину глобальной таблицы смещений, так что можно использовать как положительные, так и отрицательные смещения. Поскольку вы обращаетесь к указателям на данные (а не к самим данным), вы имеете доступ примерно к 8 000 глобальных переменных (локальные переменные находятся в регистрах или в стеке, который будет обсужден в третьей статье этой серии). А если даже этого недостаточно, то могут существовать многочисленные глобальные таблицы смещений. Этот вариант тоже обсуждается в следующей статье.

Хотя это все более компактно и читабельно (не говоря уже о том, что перемещаемо), чем загрузка данных с помощью пяти команд в последней статье, можно сделать еще лучше. В 64-битном ELF ABI таблица глобальных переменных является в действительности подмножеством большего множества, известного как таблица содержимого (table of contents). Вдобавок к созданию записей в глобальной таблице смещений, таблица содержимого может содержать переменные, которые содержат не адреса глобальных данных, а сами элементы данных. Размер и число этих переменных должно быть малым, так как таблица содержимого имеет размер всего 64К.

Чтобы объявить таблицу содержимого элементов данных, вы должны переключится на .toc раздел и произвести объявления явно. Это выглядит так:

.section .toc
name:
.tc unused_name[TC], initial_value

Это создаст элемент таблицы содержимого. name -- это идентификатор, используемый для ссылки на него внутри кода. initial_value -- это изначально присваиваемая 64-битная величина. unused_name -- это исторический реликт, который теперь ни для чего не используется в ELF системах. Вы можете выбросить его (он был включен выше только для того, чтобы помочь в чтении существующего кода), однако [TC] требуется.

Для доступа к данным, которые находятся прямо в таблице содержимого, вы должны сослаться на них, используя @toc вместо @got . @got продолжает функционировать, но он действует как и прежде, возвращая указатель к вашей величине, а не саму величину. Посмотрите на этот код:

Листинг 6. Различие между @got и @toc
### ДАННЫЕ ###

#Создать переменную my_var в таблице содержимого
.section .toc
my_var:
.tc [TC], 10

### ОПИСАНИЕ ТОЧКИ ВХОДА ###
.section .opd, "aw"
.align 3
.globl _start
_start:
        .quad ._start, .TOC.@tocbase, 0

### КОД ###
.text
._start:
        # загрузить число 10 (содержимое my_var) в регистр 3
        ld 3, my_var@toc(2) 

        # загрузить адрес  my_var в регистр 4
        ld 4, my_var@got(2)
        # загрузить число 10  10 (сожержимое my_var) в регистр 4
        ld 3, 0(4)

        # загрузить число 15 в регистр 5
        li 5, 15

        # сохранить 15 (регистр 5) в my_var при помощи ToC
        std 5, my_var@toc(2)

        # сохранить 15 (регистр 5) в my_var при помощи  GOT (смещение 
	# уже загружено в регистр 4)
        std 5, 0(4)

        # завершить выполнение со статусом 0
        li 0, 1
        li 3, 0
        sc

Как можно видеть, если вы будете искать идентификатор, который определяет данные, в разделе .toc (вместо раздела .data, где находится большинство данных), используя @toc, это даст вам смещение, которое приведет вас прямо к значению, тогда как использование @got даст вам смещение к адресу величины.

Теперь давайте рассмотри пример сложения чиселб используя значения из ToC:

Листинг 7. Сложение чисел определенных в разделе .toc
### ДАННЫЕ ПРОГРАММЫ ###
#Создать величины в таблице содержимого
.section .toc
first_value:
        .tc [TC], 1
second_value:
        .tc [TC], 2

### ОПИСАНИЕ ТОЧКИ ВХОДА ###
.section .opd, "aw"
.align 3
.globl _start
_start:
        .quad ._start, .TOC.@tocbase, 0

.text
._start:
        ## Загрузить величины из таблицы содержимого ##
        ld 4, first_value@toc(2)
        ld 5, second_value@toc(2)

        ## Выполнить сложение ##
        add 3, 4, 5

        ##Выход из программы со статусом##
        li 0, 1
        sc

Как можно видеть, используя данные из .toc, вы можете существенно уменьшить число команд, используемых в вашем коде. А также, поскольку таблица содержимого находится обычно в кэше, это значительно уменьшает и задержки при доступе к памяти.


Загрузка и сохранение множественных данных

PowerPC может также производить множественные загрузки и сохранения по одной команде. К сожалению, это процесс ограничен данными размером в одно слово (32 бита). Это очень простые команды D-Form. Вы определяете базовый адрес регистра, смещение и начальный регистр назначения. Процессор будет загружать данные во все регистры, начиная с указанного регистра назначения до регистра 31, начиная с адреса, указанного в команде и двигаясь вперед. Команды, выполняющие эту операцию lmw (load multiple world) и stmw (store multiple word). Ниже -- несколько примеров:

Листинг 8. Загрузка и сохранение множественных данных
#Начиная с адреса, указанного в регистре 10, загрузить
#следующие  32 байта в регистры 24-31
lmw 24, 0(10)

#Начиная с адреса, указанного в регистре 8, загрузить
#следующие 8 байт в регистры 30-31
lmw 30, 0(8)

#Начиная с адреса, указанного в регистре 5, загрузить
#младшие  32-бита из регистров 20-31 в следующие 
#48 байт
stmw 20, 0(5)

А теперь снова наша программа сложения чисел с использованием операций над множественными данными:

Листинг 9. Программа сложения чисел с использованием операций над множественными данными
### Данные ###
.data
first_value:
        #Используем "long" вместо "double", поскольку
        #"множественная" команда работает только 
        #с 32 битами
        .long 1  
second_value:
        .long 2

### ОПИСАНИЕ ТОЧКИ ВХОДА ###
.section .opd, "aw"
.align 3
.globl _start
_start:
        .quad ._start, .TOC.@tocbase, 0

### КОД ###
.text
._start:
        #Загрузить адрес наших данных из  GOT
        ld 7, first_value@got(2)

        #Загрузить значения в регистры 30 и 31
        lmw 30, 0(7)

        #сложить величины
        add 3, 30, 31

        #завершить
        li 0, 1
        sc

Режим "с обновлением"

Большинство load/store команд может обновлять исходный адресный регистр конечным адресом, который был использован для загрузки данных. Например, команда ldu 5, 4(8) загружает из адреса, указанного в регистре 8, плюс 4 байта в регистр 5 и затем сохраняет вычисленный адрес обратно в регистр 8. Это называется загрузка и сохранение с обновлением и может быть использовано, чтобы уменьшить число команд, требующихся для выполнения ряда операций. Я буду часто использовать это в следующей статье.


Заключение

Эффективная загрузка и сохранение критичны для эффективного кода. Знание форматов команд и доступных способов адресации поможет вам понять возможности и ограничения платформы. Форматы команд D-Form и DS-Form на PowerPC критичны для позиционно-независимого кода. Позиционно-независимый код позволяет создавать разделяемые (shared) библиотеки и позволяет вам использовать меньше команд для загрузки глобальных адресов.

Следующая статья в этой серии будет рассматривать ветвление, вызовы функций и интеграцию с кодом на C.

Ресурсы

Научиться

Получить продукты и технологии

  • С помощью trial-версии программ IBM, доступных для скачивания с developerWorks, сделайте вашу следующую разработку на Linux.

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux
ArticleID=211839
ArticleTitle=Ассемблер для Power-архитектуры, Часть 2: Искусство загрузки и сохранения на PowerPC
publish-date=04242007