Вызов подпрограммы на ассемблере из программы на С

Хорошим стилем программирования считается описание прототипа ассемблерной функции для определения аргументов функции и интерфейса между программой на С и подпрограммой на ассемблере.

Run-time модель выполнения определяет некоторые регистры как рабочие (Scratch), а некоторые – как "сохраняемые при вызове" (Call Preserved). Scratch-регистры могут использоваться в ассемблерной подпрограмме без ограничений, не нужно заботиться о восстановлении их старых значений при выходе из подпрограммы. Если рабочих регистров недостаточно, то можно использовать CallPreserved-регистры, однако при входе в функцию следует сохранить их значения, а при выходе – восстановить. Следует стремиться к тому, чтобы использовать выделенные регистры по их прямому назначению (например, для работы со стеком), поскольку компилятор, библиотечные функции и прерывания предполагают именно такое их использование.

Компилятор предполагает, что режимы работы процессора во время выполнения asm-функции не изменяются.

Пример взаимодействия подпрограмм на С и ассемблере.

Текст модуля на языке С #include <stdio.h> int a, b, c, d, e; // прототипы функций int SumC(int u, int v, int x, int y, int z); extern int SumAsm(int u, int v, int x, int y, int z); int SumC(int u, int v, int x, int y, int z) { int temp1; temp1 = u + v + x + y + z; return temp1; } int main() { a = 1; b = 5; c = 8; d = 3; e = 10; e = SumAsm(a, b, c, d, e); e = SumC(a, b, c, d, e); return 0; } Код процедуры main() с оптимизацией: … r2=10; // r2 = e r1=3; // r1 = d dm(i7,m7)=r2; // push (e) r8=5; // r8 = b r12=8; // r12 = c r4=m14; // r4 = 1 dm(i7,m7)=r1; // push (d) //сохранить a,b,c,d,e dm(_a)=r4; dm(_b)=r8; dm(_c)=r12; dm(_d)=r1; dm(_e)=r2; // вызов cjump _SumAsm (DB); dm(i7,m7)=r2; dm(i7,m7)=pc; // возврат, результат в r0 – это e modify(i7,2); //очистка стека от параметров // подготовка к следующему вызову r2=dm(_d); // r2 = d dm(i7,m7)=r0; // push (e) r12=dm(_c); // r12 = c r8=dm(_b); // r8 = b r4=dm(_a); // r4 = a dm(i7,m7)=r2; // push (d) dm(_e)=r0; // сохранить e=SumC() // вызов cjump _SumC (DB); dm(i7,m7)=r2; dm(i7,m7)=pc; dm(_e)=r0; // сохранить результат в e modify(i7,2); // очистить стек от параметров …
Код процедуры SumC без оптимизации (Debug) _SumC: // место под локальную temp и автопеременные modify(i7,-5); // полученные параметры -> в автопеременные dm(-4,i6)=r4; dm(-3,i6)=r8; dm(-2,i6)=r12; // вычисления (без оптимизации) r2=r4+r8; // r2 = u+v r1=r2+r12; // r2 = u+v+x r0=dm(1,i6); // r0 = y (i6+1) r2=r1+r0; // r2 = u+v+x+y r1=dm(2,i6); // r1 = z (i6+2) r0=r2+r1; // r0 = u+v+x+y+z dm(-6,i6)=r0; // temp = r0 // возврат i12=dm(m7,i6); jump(m14,i12) (DB); rframe; nop; Код процедуры SumC с оптимизацией (Release) _SumC: modify(i7,-4); //место под локальную temp (лишнее) r2=dm(2,i6); r2=r2+r4, r1=dm(1,i6); r2=r2+r1, i12=dm(m7,i6); jump(m14,i12) (DB), r2=r2+r12; r0=r2+r8; rframe;
Модуль с кодом процедуры SumAsm, написанный вручную #include <def21060.h> #include <asm_sprt.h> .section/pm seg_pmco; .global _SumAsm; //int SumAsm(int u, int v, int x, int y, int z) _SumAsm: r0 = r4+r8, r4 = dm(0x1,i6); // r0=u+v, r4=y; r0 = r0 + r4, r4 = dm(0x2,i6); // r0=u+v+y, r4=z; r0 = r0 + r4, i12=dm(m7, i6); // r0=u+v+y+z jump (m14, i12) (DB), r0 = r0 + r12; // r0=Sum, возврат nop; rframe;

Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: