Wywołanie w C++ funkcji zaimplementowanej w Asemblerze

Odpowiedz Nowy wątek
2013-10-25 11:25
0

Mój program (tylko taki testowy, nic konkretnego nie robi) korzysta z funkcji asemblerowej. Wygląda to w ten sposób:
main.h:


#pragma once
#include <Windows.h>
extern "C" int Dodaj( int* tab, int a1, int a2);

main.cpp:


#include <iostream>
#include "naglowek.h"

using namespace std;

int main()
{
    int result = 0;
    int tab[2] = {2,3};
    result = Dodaj(tab, 2, 2);
    std::cout << result;
    getchar();
    return 0;
}

Natomiast procedure.asm:

.386 

.MODEL FLAT, C

.DATA

a1 dd 0
a2 dd 0

.CODE

Dodaj proc
    push ebp
    mov ebp, esp

    xor eax, eax
    mov ebx, [ebp+8]
    mov edx, [ebp+12]
    mov ecx, [ebp+16]
    mov [a1], edx
    mov [a2], ecx
    xor ecx, ecx
petla:
    cmp ecx, a2
    jae koniec_petli

    add eax, [ebx+4*ecx]

    inc ecx
    jmp petla

    koniec_petli:
    pop ebp
    ret
Dodaj endp

END Dodaj

Jeszcze jest plik .def ale nie wrzucam. Funkcja ma dodawać elementy tablicy. Testuje to tylko po to, żeby potem w przypadku trudniejszej procedury nie wyłożyć się na podstawach. Tak jak tutaj właśnie się wyłożyłem.

No i problem jest taki:

  1. Jeśli w pętli porównuje cmp ecx, a1 to niby dobrze.
    EDIT: W registers sprawdziłem to w EDX jest 00000001 niezależnie czy wprowadzę jako parametr 1 ,2 czy 10. Przez debugger sprawdzam i pętla zawsze wykonuje się tylko raz. A wynik jest taki jakby wykonała się tą zadaną ilość razy o.0 nie rozumiem.
  2. Jeśli w pętli porównuje cmp ecx, a2 to wywala access violation przy dodawaniu do EAX.

Nie umiem stwierdzić, czy błąd jest w kwestii przekazania argumentów do procedury czy dopiero potem w kodzie.


edytowany 3x, ostatnio: Mossar, 2013-10-25 11:59
Czy szukałbyś odpowiedzi na swoje pytanie pod "asembler i c++" czy użyłbyś bardziej rozbudowanego zapytania? ;] - Shalom 2013-10-27 09:01

Pozostało 580 znaków

2013-10-25 13:06
0

Powinno być:

petla:
    cmp ecx, [a2]

Bo zapewne chodziło ci o zawartość a2 a nie o adres.

PS. Kod da się znacznie uprościć:

.386 

.MODEL FLAT, C

.CODE
Dodaj proc
   push ebp
   mov ebp, esp

   mov ebx, [ebp+8]
   mov ecx, [ebp+12]
   xor eax, eax

   petla:
      add eax, [ebx-4+4*ecx]
   loop petla
   pop ebp
   ret
Dodaj endp

END Dodaj
edytowany 1x, ostatnio: lukasz1235, 2013-10-25 13:25

Pozostało 580 znaków

2013-10-25 15:49
0

Dzięki za uproszczenie :) Ale problem dalej jest z pobraniem 3 parametru. Gdybym tą część:

....
   mov ebx, [ebp+8]
   mov ecx, [ebp+12]
   xor eax, eax

   petla:
      add eax, [ebx-4+4*ecx]
...

zamienił tą:

....
   mov ebx, [ebp+8]
   mov edx, [ebp+12]
   mov ecx, [ebp+16]
   xor eax, eax

   petla:
      add eax, [ebx-4+4*ecx]
...

To wyskakuje access violation na

 add eax, [ebx-4+4*ecx]

.
Wczytywanie parametrów raczej dobrze, bo właśnie sprawdziłem wartości ecx i edx po pobraniu ich i maja dokładnie takie jakie były przesłane. Ale z jakiegoś powodu jak odwołuje się do ecx zapełnionego drugim parametrem, a nie pierwszym to wyskakuje błąd ;/

W ogóle to chyba temat się nadaje do działu "inne języki programowania".


edytowany 1x, ostatnio: Mossar, 2013-10-25 16:01

Pozostało 580 znaków

2013-10-25 16:02
0

Ciekawe. Na pewno funkcję wywołujesz tak?

result = Dodaj(tab, 2, 2);

Jeśli tak to sprawdź debuggerem jaką wartość ma rejestr ecx.

Pozostało 580 znaków

2013-10-25 16:12
0

EBX = 71890000
EDX = 00000001
ECX = 0037FCF8

Takie wartości są zaraz po instrukcjach mov. A więc zdecydowanie nie to co ma być. Ale co dziwnego się dzieje to to, że jak tak sobie cisnę tym debuggerem to wchodzi w "Disassembly" w Visualu po czym znowu wraca do tej mojej procedury i wtedy już:
EDX = 00000002
ECX = 00000002

Tak jakby przed w ogóle wywołaniem procedury w result = Dodaj(tab, 2, 2); ona się wykonuje samoczynnie o.0 Postawiłem breakpoint przed wywołaniem tej procedury i pojawił się error jeszcze przed wejsciem na breakpointa. A znacznik był w pliku. asm.. Czyli w jakiś sposób musi się ta procedura uruchamiać bez wywołania jej.


edytowany 2x, ostatnio: Mossar, 2013-10-25 16:15

Pozostało 580 znaków

2013-10-25 16:18

Podrzuć mi skompilowaną binarkę. Nie mam teraz pod ręką Windowsa, ale może coś zauważę.

(wrzuć na forum najlepiej, o ile się da - tzn. do @Mossar) - msm 2013-10-25 16:19

Pozostało 580 znaków

2013-10-25 16:38
0

Nie do końca wiedziałem co mam posłać, więc daje cały projekt. http://www.sendspace.com/file/787odc Ma ponad 10mb, więc jak mi wyjaśnisz co mam wyodrębnić z projektu to Ci wyślę.

Taka luźna dygresja - może program się nie zaczyna od maina tylko od procedury w .asm? Mogłem coś takiego przypadkowo ustawić w properties tych dwóch projektów? Bo solucja się składa z dwóch projektów. Jeden zawiera .asm i .def, drugi .h i .cpp

.exe: http://www.sendspace.com/file/8iq20p


edytowany 2x, ostatnio: Mossar, 2013-10-25 16:46
binarke czyli .exe - fasadin 2013-10-25 16:43

Pozostało 580 znaków

2013-10-25 17:24
0
Mossar napisał(a):

Taka luźna dygresja - może program się nie zaczyna od maina tylko od procedury w .asm? Mogłem coś takiego przypadkowo ustawić w properties tych dwóch projektów?
Tak, po raz pierwszy funkcja Dodaj jest wywoływana przez DllEntryPoint.

Dzieki za całą tą pomoc. Ale jeszcze jedno pytanie mam.. Jak zmienić DLLEntryPoint, żeby nie wywoływał tej procedury? Gdzieś coś czytałem o stdcall, ale po wpisaniu stdcall przed nazwą funkcji mam błedy. - Mossar 2013-10-25 17:42
Gdzieś we właściwościach projektu powinno być. - lukasz1235 2013-10-25 17:46
Entry point jest, ale nie za bardzo mi wychodzi jego ustawianie. Albo błędy linkera albo dalej to samo. Także jak ktoś tutaj wie jak to zrobić, to proszę o pomoc, bo taka pierdoła, a siedzę cały dzień dzisiaj przy tym - Mossar 2013-10-25 18:21
A nie ma nigdzie opcji żeby wyłączyć entry point? - lukasz1235 2013-10-25 18:22
No i tu się pojawia problem, bo mam ustawione no entry point: YES/NOENTRY , a problem jak występował tak występuje - Mossar 2013-10-25 18:25
jak ustawiam STDCALL to mam takie errory: error LNK2019: unresolved external symbol [email protected] referenced in function _main 2>D:\Visual Studio 2010\Projects\JaLab5\Debug\JA5.exe : fatal error LNK1120: 1 unresolved externals - Mossar 2013-10-25 18:26

Pozostało 580 znaków

2013-10-27 01:24
0

Ostatnie moje pytanie. Udało mi się przekazać do procedury dwuwymiarową tablicę oraz utworzyć w .asm nową tablicę dwywymiarową:

msk dd 500 dup(500 dup (0))

Następnie wykonuje wszelkie przekształcenia i chce zwrócić tą tablicę spowrotem do C++. Robię to w ten sposób:

lea eax, msk
ret

I teraz zaczynają się schody.

extern "C" int* __stdcall Dodaj(int* tab, int hei, int wid); 

int tab[100][100];
int *tab2;
//...
tab2 = Dodaj(&(tab[0][0]), 100,100);

    for(int k = 0; k <100 ; k++)
    {
        for(int l = 0; l <100; l++)
        {
            result += tab2[k*l+l]; //tutaj mam pytanie, czy muszę odbierać tą tablicę jako tablicę jednowymiarową i przechodzić po 
                                         //niej w taki cwaniacki sposób czy dam radę jakoś tak to ustawić, żebym mógł 
                                         //normalnie działać na dwuwymiarowej
        }
    }

A więc teoretycznie działa, ale w ramach czytelności kodu chciałbym, żeby ta tab2 była dwuwymiarowa, a nie jednowymiarowa, udająca dwuwymiarową.
Także bardziej jest to pytanie natury C++owej i aż mi wstyd, że nie potrafię tego rozwikłać. Oczywiście mógłbym napisać funkcje, która by przekształcała tą jednowymiarową tablicę w dwuwymiarową, ale pewnie musi się dać to zrobić od razu.


edytowany 5x, ostatnio: Mossar, 2013-10-27 01:35

Pozostało 580 znaków

2013-10-27 01:56
0

Wszystkie tablice de facto są jednowymiarowe po zejściu na poziom asemblera.Tak więc ciąg 12 bajtów może robić za tablicę char[12],albo [2][6] tudzież [3][4],ba,nawet i [3][2][2].Cała ta wymiarowość tablic jedynie ułatwia obliczanie adresu do zapisu/odczytu.


"Sugeruję wyobrazić sobie Słońce widziane z orbity Merkurego, a następnie dupę tej wielkości. W takiej właśnie dupie specjalista ma teksty o wspaniałej atmosferze, pracy pełnej wyzwań i tworzeniu innowacyjnych rozwiązań. Pracuje się po to, żeby zarabiać, a z resztą specjalista sobie poradzi we własnym zakresie, nawet jeśli firma mieści się w okopie na granicy obu Korei."
-somekind,
konkretny człowiek-konkretny przekaz :]

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0