Aktualności:

Nowy polski projekt BOINC - Universe@Home

Menu główne

ASM + C - problem z linkowaniem

Zaczęty przez Rysiu, 09 Sierpień 2014, 17:51

Rysiu

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?

matszpk

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).

Rysiu

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

matszpk

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.

Rysiu

Ale zaraz, zaraz...

Mam tam coś takiego:

DWORD *j = &Length;

Skąd niby się wzięło &Length? Przecież nigdzie nie jest zadeklarowane.