Andrzej Skoczylas

Asembler 386 w Borlad C++

[ASM_BCC3.ZIP]

Asembler


Sporą niedogodnością jest fakt, że kompilator Borland C++ (v3.x), mimo opcji generowania kodu 80386, nie rozpoznaje właściwych dla tego procesora rozkazów asemblerowych wpisanych przy pomocy instrukcji "asm". Można używać w ten sposób tylko 16-bitowych rozkazów 286, co znacznie obniża przydatność wbudowanego asemblera.

Przykład:

asm add eax,edx // BŁĄD

386 rozpoznaje rozkazy rozpoczynające się bajtem 66h jako rozszerzone, czyli odnoszące się do podwójnych słów (dword) i 32-bitowych rejestrów. Można więc oszukać kompilator (niezależnie od opcji generowanego kodu). Wystarczy poprzedzić rozkaz 16-bitowy bajtem rozszerzenia:

asm db 0x66 // dla 286 jest to dana
asm add ax,dx // uzyskujemy add eax,edx

Dla wygody możemy utworzyć makro, którego będziemy używać dla uzyskania rozkazów rozszerzonych:

#define xasm asm db 0x66; asm

Przykłady:

xasm xor dx,dx // xor edx,edx
xasm shl ax,16 // shl eax,16
xasm mov dx,WORD PTR[xLong] // mov edx,DWORD PTR[xLong]

Sprawa trochę się komplikuje, gdy operujemy wartościami natychmiastowymi. Aby np. wpisać liczbę typu long do rejestru 32-bitowego należy użyć dodatkowej danej 16-bitowej (dw) jako starszego słowa naszej wartości natychmiastowej.

Przykład:

xasm mov ax,0x1234 // mov eax,0x77881234h
asm dw 7788h

Jest to spowodowane tym, że w rozkazie 16-bitowym kompilator generuje daną natychmiastową 16-bitową. Procesor, odczytując rozkaz jako 32-bitowy, pobiera dodatkowo dwa najstarsze bajty wartości natychmiastowej.

Sposób ten może być szczególnie przydatny, gdy np. optymizujemy we wbudowanym asemblerze Borland C procedurę operującą na zmiennych 32-bitowych (long). Możemy wykorzystać dokładne mnożenie i dzielenie, bardzo wygodne staje się przesuwanie bitowe.

Właściwie należałoby jeszcze sprawdzić, czy procesor to przynajmniej 386...

Stronę opracował Michał Szulowski