Mam problem z kompilacją wstawki asemblerowej w kodzie C.
Wziąłem program ze strony: http://users.tmok.com/~pla/Lychrel/196xampl_vs.zip
Oczywiście nie chciał chodzić na Linuxie z kilku względów.
Musiałem zmienić składnię asemblera z Intelowskiej na AT&T (przepisałem tych 300 linijek).
Mam jednak coś takiego:
int faa8x64a(void *dat1, void *dat2, int leng)
{
const unsigned long long int C0x0000000000000001 = 0x0000000000000001;
const unsigned long long int C0x0000000100000000 = 0x0000000100000000;
const unsigned long long int C0x0606060606060606 = 0x0606060606060606;
const unsigned long long int C0x0F0F0F0F0F0F0F0F = 0x0F0F0F0F0F0F0F0F;
const unsigned long long int C0x76F6F6F676F6F6F6 = 0x76F6F6F676F6F6F6;
const unsigned long long int C0x7FFFFFFF7FFFFFFF = 0x7FFFFFFF7FFFFFFF;
unsigned long long int flag = 0xFFFFFFFFFFFFFFFF;
asm("mov $leng, %edx");
asm("mov ($dat1), %edi");
asm("mov %edx, %esi");
asm("add %edi, %edx");
asm("add %edi, %esi");
asm("sub $32, %edx");
asm("mov ($dat2), %ebx");
asm("mov $0, %eax");
asm("pxor %mm7, %mm7");
asm("nop");
asm("nop");
asm("nop");
// start outer loop
asm("faa0:");
// try to pre-cache the data for the next loop iteration
asm("mov -48(%edx), %eax");
asm("mov 48(%edi), %eax");
// load next reversed section
asm("mov 24(%edx), %eax");
asm("mov 28(%edx), %ecx");
asm("bswap %eax");
asm("bswap %ecx");
asm("movd %eax, %mm1");
asm("movd %ecx, %mm0");
asm("mov 16(%edx), %eax");
asm("mov 20(%edx), %ecx");
asm("bswap %eax");
...
Całość wywala się na linkowaniu... System zwraca mi błędy:
Cytat/tmp/cckXS6V6.o: In function `faa8x64a(void*, void*, int)':
engine6.cpp:(.text+0x69): undefined reference to `leng'
engine6.cpp:(.text+0x6f): undefined reference to `$dat1'
engine6.cpp:(.text+0x7e): undefined reference to `$dat2'
...
Jak prawidłowo odnosić się do zmiennych z C w tym Asemblerze?
Próbowałem na różne sposoby np. tak:
asm("mov $leng, %edx");
asm("mov leng, %edx");
asm("mov ($leng), %edx");
asm("mov (leng), %edx");
i zawsze mam ten sam błąd z linkowaniem. Jak zrobić to prawidłowo?
problemem jest tu prostu brak symboli (leng, dat1, dat2). Musisz je zdefiniować w kodzie jako etykiety lub jako wartość za pomocą ".equ leng, wartość". sprawdź czy nie zapomniałeś deklaracji lub definicji zmiennych w oryginalnym kodzie. każda nazwa w instrukcjach jest traktowana jako symbol (może być globalny, lokalny) i musi być gdzieś on zdefiniowany (w tym kodzie lub w innym pliku).
Rozwiązałem problem trochę inaczej....
Przerobiłem program z C za pomocą GCC do Asemblera. Później z poziomu Asemblera ręcznie zmieniłem nazwy zmiennych na adresy im odpowiadające i skompilowałem kod Asemblera do kodu binarnego. Działa.
Wydajność jednak mnie nie powala i szukam szybszego rozwiązania. Znalazłem kod zoptymalizowany dla Pentium 4 (ten co mam wykorzystuje jedynie MMX).
Kod ten jednak zaczyna się od:
char ReverseAddandCheck()
{
DWORD *j = &Length;
char lc_Rem[128], *lcRem = lc_Rem;
INT128 c14141414141414141414141414141414 = {0x14141414,0x14141414,0x14141414,0x14141414};
INT128 c76767676767676767676767676767676 = {0x76767676,0x76767676,0x76767676,0x76767676};
INT128 c7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F = {0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F,0x7F7F7F7F};
ULARGE_INTEGER cFFFFFFFFFFFFFFFF, cF6F6F6F6F6F6F6F6;
cF6F6F6F6F6F6F6F6.LowPart = 0xF6F6F6F6;
cF6F6F6F6F6F6F6F6.HighPart = 0xF6F6F6F6;
cFFFFFFFFFFFFFFFF.LowPart = 0xFFFFFFFF;
cFFFFFFFFFFFFFFFF.HighPart = 0xFFFFFFFF;
...
Według komentarzy jest to napisane zjadliwie dla kompilatora MSVC 6.0. Jak zapisać te linijki aby łyknęło to GCC/G++?
Cały kod znajduje się pod linkiem: http://users.tmok.com/~pla/Lychrel/e_goldst.c (http://users.tmok.com/~pla/Lychrel/e_goldst.c)
imho należy tylko definicje typów DWORD, INT, WORD i itp. uważaj na ULONG (w MSVC w 64-bit jest on 32-bitowy). i to by było na tyle.
jeśli korzystasz ze stawek assemblera napisanych dla MSVC, to możesz skorzystać Intel syntax w GNU as za pomocą dyrektywy ".intel_syntax noprefix"
wtedy należy tylko poprawić błędy składniowe pododawać deklaracje symboli i tylko tyle. w kodzie C możesz stosować też inline assembler ale to trochę trudniejsze.
Zapoznaj się też z konwencjami wywoływania funkcji w C dla x86 i x86_64 dla linux i win.
Ale zaraz, zaraz...
Mam tam coś takiego:
DWORD *j = &Length;
Skąd niby się wzięło &Length? Przecież nigdzie nie jest zadeklarowane.