【问题标题】:How to pass data from C to assembly如何将数据从 C 传递到程序集
【发布时间】:2017-06-19 13:15:05
【问题描述】:

我制作了一个分为两部分的程序。 第一部分是用 C 语言编写的,它从用户那里获取数据。第二个是用汇编及其制作操作编写的。 我在将数据从动态分配的数组传递到汇编模块时遇到问题。程序运行不正常。我做错了什么?

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

extern "C" near void licz_sr( int* );
extern "C" near void licz_znaki( char* );

int *tablica_liczb_dynamiczna;
char tablica_znakow[28]; //[0] = ilosc, [1] = kod szukany, [27] = ilosc wystapien
int wielkosc_tablicy = 0;
int kod;

int menu(), losuj_liczby(), losuj_znaki(), licz_srednia(), sprawdz_ilosc_znakow();
void wczytaj_liczby(), wczytaj_znaki();

int main() {
    srand(time(NULL));

    //tablica_liczb[0] = 5;
    tablica_znakow[0] = 25;
    menu();

    return 0;
}

int menu(){

    printf("\n\n\nCo mam zrobic?\nW = Wyliczyc srednia z losowej tablicy\nP = Policzyc ilosc znakow w losowej tablicy\nX = Wyjsc z programu\n");

    kod = getchar();
    getchar();

    if (kod == 87 || kod == 119) {
        //losuj_liczby();
        wczytaj_liczby();
        //licz_srednia();
    }
    else if (kod == 80 || kod == 112){
        //losuj_znaki();
        wczytaj_znaki();
        sprawdz_ilosc_znakow();
    }
    else if (kod == 88 || kod == 120){
        return 0;
    }
    menu();
}

void wczytaj_liczby()
{
    printf("Ile znakow wprowadzic? ");
    scanf("%d",&wielkosc_tablicy);
    printf("wielkosc tab: "); printf("%d",wielkosc_tablicy);

    tablica_liczb_dynamiczna = (int*)malloc(wielkosc_tablicy * sizeof(int));

    for(int i = 0; i < wielkosc_tablicy; i++){  
        tablica_liczb_dynamiczna[i] = NULL;
    }

    printf("\n\nWczytaj liczby:");

    for(int j = 0; j < wielkosc_tablicy; j++)

    {
        scanf("%d", &tablica_liczb_dynamiczna[j]);

        printf("\n");
        printf("%d", j);printf("element tab "); printf("%d",tablica_liczb_dynamiczna[j]);
        printf("\n");
        tablica_liczb_dynamiczna[j] = tablica_liczb_dynamiczna[j]-48;
    }
    licz_srednia();
}

void wczytaj_znaki()

{

    for (int i =2; i < tablica_znakow[0]+2; i++)

    {

        tablica_znakow[i] = NULL;

    }

    printf("\n\nWczytaj znaki:");

    char polecenie[25];

    fgets( polecenie, 25, stdin );

    for (int j =2; j < tablica_znakow[0]+2; j++)

    {

        tablica_znakow[j] = polecenie[j-2];

    }

}



int licz_srednia()

{
    licz_sr(tablica_liczb_dynamiczna);



    //printf("\n\nSrednia jest rowna: "); printf("%c", tablica_liczb[6]+48); printf(", a reszta jest rowna: "); printf("%c", tablica_liczb[7]+48);

    printf("\n\nSrednia jest rowna: "); printf("%c", tablica_liczb_dynamiczna[6]+48); printf(", a reszta jest rowna: "); printf("%c", tablica_liczb_dynamiczna[7]+48);

    //cout << "Srednia jest rowna: " << tablica_liczb_dynamiczna[6]+48 << ", a reszta: " << tablica_liczb_dynamiczna[7]+48 << endl;

    return 0;

}


int sprawdz_ilosc_znakow()

{

    printf("\n\nWystapienia jakiego znaku mam liczyc? ");

    tablica_znakow[1] = getchar();

    getchar();

    //printf("\n\n");

    licz_znaki(tablica_znakow);



    printf("\nZnak \""); printf("%c", tablica_znakow[1]); printf("\" wystapil "); printf("%c", tablica_znakow[27]+48); 

    if (tablica_znakow[27] != 1)        printf(" razy.");

    else                                            printf(" raz.");

}

和装配部分。

.model small, C


Dane            SEGMENT

Tablica         DB          (?)
Ilosc           DB          (?)

Dane            ENDS


PUBLIC licz_znaki

.code


licz_znaki    PROC near


            push    bp
            mov     bp, sp
            mov     di, [bp+4]
            ; [bp+4] = adres
            ; [di] = liczba
            ; [bp+12] = tab[1]
            ; [bp+16] = tab[2]
            ; [bp+20] = tab[3]
            ; [bp+24] = tab[4]
            xor     cx, cx
            mov     cl, [di]
            inc     di
            ;inc        di
            xor     ax, ax
            xor     bx, bx
            xor     dx, dx
            mov     ah, [di]            ;w ah jest znak, którego szukamy
            inc     di
            ;inc        di
Petla_z:
            mov     al, [di]            ;w ah jest aktualny znak z tablicy
            cmp     al, ah
            jz          Dodaj_do_wyniku
            Powrot_do_petli:
            inc     di
            ;inc        di
            loop        Petla_z

Dodaj_do_wyniku:
            jcxz        Koncowka
            inc     bx              ;bh przechowuje ilosc wystapien
            jmp     short   Powrot_do_petli

Koncowka:
            mov     [di], bx

            pop     bp
            ret

licz_znaki ENDP

PUBLIC licz_sr

.code


licz_sr    PROC near


            push    bp
            mov     bp, sp
            mov     di, [bp+4]
            mov     bx, [di]
            ; [bp+4] = adres
            ; [di] = liczba
            ; [bp+12] = tab[1]
            ; [bp+16] = tab[2]
            ; [bp+20] = tab[3]
            ; [bp+24] = tab[4]
            xor     cx, cx
            mov     cl, [di]
            inc     di
            inc     di
            xor     ax, ax
            xor     dx, dx
Petla_l:
            add     ax, [di]
            inc     di
            inc     di
            loop        Petla_l

            div     bx

            mov     [di], ax
            inc     di
            inc     di
            mov     [di], dx        ;wj

            pop     bp
            ret

licz_sr ENDP


end

翻译的C模块: 说明:具有正常数组(非动态)的程序正在将数据下载到[8] 元素数组。用户可以输入5 数字。组装模块将平均值返回到表的[6] 元素,将其余部分返回到表的[7] 元素。然后 C 模块使用 printf 函数输出表的 [7] 和 [6] 元素。

 #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>

    extern "C" near void count_averageExtern( int* );
    extern "C" near void count_characters( char* );

    int *dynamic_arrau;
    //char tablica_znakow[28]; //[0] = ilosc, [1] = kod szukany, [27] = ilosc wystapien
    int size_of_array = 0;
    int code;

    int menu(), count_average(), sprawdz_ilosc_znakow();
    void download_numbers(), wczytaj_znaki();

    int main() {
        srand(time(NULL));

        //tablica_liczb[0] = 5;
        tableOfCharacters[0] = 25;
        menu();

        return 0;
    }

    int menu(){

        printf("\n\n\nWhat to do?\nW = average\nP = not important\nX = exit\n");

        code = getchar();
        getchar();

        if (code == 87 || code == 119) {
            //losuj_liczby();
            download_numbers();
            count_average();
        }
        /*else if (kod == 80 || kod == 112){
            //losuj_znaki();
            wczytaj_znaki();
            sprawdz_ilosc_znakow();
        }*/
        else if (kod == 88 || kod == 120){
            return 0;
        }
        menu();
    }

    void download_numbers()
    {
        printf("How many numbers input? ");
        scanf("%d",&size_of_array);

        dynamic_arrau = (int*)malloc(size_of_array * sizeof(int));

        for(int i = 0; i < size_of_array; i++){ 
            dynamic_arrau[i] = NULL;
        }

        printf("\n\Input numbers:");

        for(int j = 0; j < size_of_array; j++)

        {
            scanf("%d", &dynamic_arrau[j]);

            printf("\n");
            tablica_liczb_dynamiczna[j] = tablica_liczb_dynamiczna[j]-48;
        }
        licz_srednia();
    }

    /*void wczytaj_znaki() {

        for (int i =2; i < tablica_znakow[0]+2; i++)

        {

            tablica_znakow[i] = NULL;

        }

        printf("\n\nWczytaj znaki:");

        char polecenie[25];

        fgets( polecenie, 25, stdin );

        for (int j =2; j < tablica_znakow[0]+2; j++)

        {

            tablica_znakow[j] = polecenie[j-2];

        }

    }
    */


    int count_average()

    {
        count_averageExtern(dynamic_arrau);
        //printf("\n\nSrednia jest rowna: "); printf("%c", tablica_liczb[6]+48); printf(", a reszta jest rowna: "); printf("%c", tablica_liczb[7]+48);
        printf("\n\nAverage: "); printf("%c", dynamic_arrau[6]+48); printf(", and rest of division: "); printf("%c", dynamic_arrau[7]+48);
        return 0;
    }


   /* int sprawdz_ilosc_znakow()

    {

        printf("\n\nWystapienia jakiego znaku mam liczyc? ");

        tablica_znakow[1] = getchar();

        getchar();

        //printf("\n\n");

        licz_znaki(tablica_znakow);



        printf("\nZnak \""); printf("%c", tablica_znakow[1]); printf("\" wystapil "); printf("%c", tablica_znakow[27]+48); 

        if (tablica_znakow[27] != 1)        printf(" razy.");

        else                                            printf(" raz.");

    }*/

翻译后的组装模块:

    .model small, C


    Data        SEGMENT

    Tablica         DB          (?)
    Ilosc           DB          (?)

    Data        ENDS


   /* PUBLIC licz_znaki

    .code


    licz_znaki    PROC near


                push    bp
                mov     bp, sp
                mov     di, [bp+4]
                ; [bp+4] = adres
                ; [di] = liczba
                ; [bp+12] = tab[1]
                ; [bp+16] = tab[2]
                ; [bp+20] = tab[3]
                ; [bp+24] = tab[4]
                xor     cx, cx
                mov     cl, [di]
                inc     di
                ;inc        di
                xor     ax, ax
                xor     bx, bx
                xor     dx, dx
                mov     ah, [di]            ;w ah jest znak, którego szukamy
                inc     di
                ;inc        di
    Petla_z:
                mov     al, [di]            ;w ah jest aktualny znak z tablicy
                cmp     al, ah
                jz          Dodaj_do_wyniku
                Powrot_do_petli:
                inc     di
                ;inc        di
                loop        Petla_z

    Dodaj_do_wyniku:
                jcxz        Koncowka
                inc     bx              ;bh przechowuje ilosc wystapien
                jmp     short   Powrot_do_petli

    Koncowka:
                mov     [di], bx

                pop     bp
                ret

    licz_znaki ENDP
    */
    PUBLIC count_averageExtern

    .code


    count_averageExtern    PROC near


                push    bp
                mov     bp, sp
                mov     di, [bp+4]
                mov     bx, [di]
                ; [bp+4] = addres
                ; [di] = number
                ; [bp+12] = tab[1]
                ; [bp+16] = tab[2]
                ; [bp+20] = tab[3]
                ; [bp+24] = tab[4]
                xor     cx, cx
                mov     cl, [di]
                inc     di
                inc     di
                xor     ax, ax
                xor     dx, dx
    Loop_l:
                add     ax, [di]
                inc     di
                inc     di
                loop        Loop_1

                div     bx

                mov     [di], ax
                inc     di
                inc     di
                mov     [di], dx        ;wj

                pop     bp
                ret

    count_averageExtern ENDP


    end

// 中不是程序的重要部分。但我认为仍然需要理解想法。

我在 Dos shell 中使用 Broland C(BC)。它工作正常。该程序应从用户那里获取数据(用户确定数字的数量)。下载的数据保存在动态数组中。然后在汇编模块程序中计算数组中数据的平均值并返回值。使用普通数组很容易,但使用动态数组有点棘手……我不知道如何开始。

【问题讨论】:

  • “它不起作用”不是错误描述。请告诉我们您希望该程序做什么以及会发生什么。
  • 解密我们的代码并不容易,因为它使用了一种我不知道的语言中的标识符和 cmets。一般来说,如果你用英文发布代码,你会增加获得有用答案的机会。
  • assembly 的描述要求你也标记指令集/架构。
  • 提示:我认为您可以通过将波兰变量名称转换为英语变量名称来增加重新打开的可能性。

标签: c assembly


【解决方案1】:

没有通用答案,因为它是特定于实现的。阅读C11 标准(草案n1570),您可能不会看到任何提及x86。

您应该阅读与您的特定系统、处理器和 C 编译器相关的 ABIcalling conventions 的文档。一些编译器可能遵循不同调用约定(例如,使用每个函数注释或编译器配置或#pragma-s)。对于 x86,请先阅读(各种)x86 calling conventions 上的 wikipage(例如 cdeclfastcall 在 16 位模式下等...)

如果用GCC 编译你的mycsource.cC 代码,你可以用gcc -fverbose-asm -Wall -O1 -S mycsource.c 编译并研究生成的汇编文件mycsource.s 以了解对汇编函数的调用。你也可以使用Inline Assembly Language in C Code

如果您不使用 GCC,请尝试让您的 C 编译器发出并保留汇编代码并研究它(并理解、猜测或检查与您的问题相关的调用约定)。如果这不可能,请使用一些反汇编程序(或调试器的反汇编工具)。

【讨论】:

  • 我对您的答案投了反对票,因为它是非答案。它不包含任何对 OP 有用的东西。也许您打算写评论?
  • 不,我的意思是一个答案。回答“不可能有一个普遍的答案”确实是一个合理的答案(大多数涉及undefined behavior 的问题——这个问题不是——只能得到这样的答案)。此外,我在第二段中给出了有用的提示。
  • AFAIK gcc 不支持 16 位 x86,因此 gcc 不会帮助找出 ABI。
  • @BasileStarynkevitch OPs 具体问题很可能有答案——我们只需要弄清楚他使用的是什么编译器。
  • @fuz : 根据最新删除的答案和问题更新,他在DOS下使用Borland C/C++。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-06
  • 1970-01-01
  • 2011-06-25
  • 2013-09-05
  • 2015-10-20
  • 1970-01-01
相关资源
最近更新 更多