Написание на языке Ассемблера функций-элементов С++
Хотя можно написать функцию-элемент класса С++ целиком на языке Ассемблера, это далеко не просто. Например, все функ- ции-элементы классов С++ имеют "откорректированные" имена, что обеспечивает безопасную по согласованности типов компоновку функ- ций и делает возможным переопределение функций, а ваша ассемблер- ная функция должна знать в точности, какое имя С++ ожидает для данной функции-элемента. Для доступа к переменным-элементам вы должны подготовить в ассемблерном коде определение STRUC, опреде- ляющее все переменные-элементы с точно совпадающими размерами и расположением. Если ваш класс является производным, то могут су- ществовать и другие переменные-элементы, производные от базового класса. Даже если класс не является производным (порожденным), то расположение переменных-элементов в памяти изменяется в случае, если класс этот включает в себя какие-либо виртуальные функции.
Если вы пишете функцию на встроенном Ассемблере, Borland С++ может взять на себя эти вопросы. Однако если вы работаете на язы- ке Ассемблера отдельно (например, переделываете уже имеющийся код), то существуют некоторые методы, позволяющие упростить эту работу.
Создайте определение фиктивной функции С++ для ассемблерной функции. Это определение удовлетворит компоновщик, так как будет содержать откорректированное имя функции-элемента. Эта фиктивная функция будет вызывать ассемблерную функцию и передавать ей пере- менные-элементы и прочие параметры. Так как ассемблерный код бу- дет иметь все нужные ему параметры посредством аргументов, вы мо- жете не заботиться об изменениях в определении класса. Ваша ассемблерная функция может быть описана в коде С++ как extern "C", что показано в примерах. Например (countadd.cpp):
class count_add { // Частные переменные-элементы (private) int access_count; // число обращений int count; // текущий счетчик public: count_add(void) { access_count=0; count=0; } int get_count (void) {return Count;}
// Две функции, которые будут фактически написаны на // Ассемблере:
void increment(void); void add(int what_to_add=-1); // Отметим, что умолчание влияет только // на вызовы add; оно не влияет на код add }
extern "C" { // Для создания уникальных и осмысленных имен // ассемблерных подпрограмм прибавим имя класса к // имени ассемблерной подпрограммы. В отличие от прочих // ассемблеров, Турбо Ассемблер не имеет проблем с // длиной имен. void count_add_increment(int *count); // Мы передадим // указатель на // переменную count. // Ассемблер выполнит // увеличение. void count_add_add(int *count,int what_to_add); }
void count_add::increment(void) { count_add_increment(&count); }
void count_add(int what_to_add) { count_add(&count, int what_to_add); }
Ваш ассемблерный модуль, определяющий подпрограммы count_add _increment и count_add_add, должен иметь вид (COUNTADD.ASM):
.MODEL small ; выбор модели small (ближние код и данные) .CODE PUBLIC _count_add_increment _count_add_increment PROC ARG count_offset:word ; Адрес переменной-элемента push bp ; Сохранение записи активации ; вызывающей программы mov bp,sp ; Установка собственной записи ; активации mov bx,[count_offset] ; Загрузка указателя inc word ptr [bx] ; Увеличение переменной-элемента pop bp ; Восстановление записи активации ; вызывающей программы _count_add_increment ENDP
PUBLIC _count_add_add _count_add_add PROC ARG count_offset:word,what_to_add:word push bp mov bp,sp mov bx,[count_offset] ; Загрузка указателя mov ax,[what_to_add] add [bx],ax pop bp ret _count_add_add ENDP
end
Используя данный метод, вы можете не беспокоиться об измене- ниях в определении класса. Даже если вы добавляете или удаляете переменные-элементы, делаете этот класс производным или добавляе- те виртуальные функции, вам не требуется изменять ассемблерный модуль. Переассемблировать модуль нужно только в случае изменения структуры переменной-элемента count, либо если вы ходите сделать версию данного класса для модели памяти large. Переассемблирова- ние в этих случаях необходимо, поскольку при обращении к перемен- ной-элементу count вы имеете дело с сегментом и смещением.
Содержание раздела