5.4.3. 言語間の呼び出しのサンプル

以下のセクションでは、複数言語の呼び出しを混用する方法を示すサンプルコードを紹介します。

C 言語からのアセンブリ言語の呼び出し

Example 5.4Example 5.5 では、アセンブリ言語サブルーチンへの呼び出しを使用して 1 つのストリングを別のストリングの上にコピーする C プログラムを示しています。

Example 5.4. C 言語からのアセンブリ言語の呼び出し

#include <stdio.h>
extern void strcopy(char *d, const char *s);
int main()
{   const char *srcstr = "First string - source ";
    char dststr[] = "Second string - destination ";
/* dststr is an array since we’re going to change it */
    printf("Before copying:\n");
    printf("  %s\n  %s\n",srcstr,dststr);
    strcopy(dststr,srcstr);
    printf("After copying:\n");
    printf("  %s\n  %s\n",srcstr,dststr);
    return (0);
}

Example 5.5. アセンブリ言語を使用したストリングコピーサブルーチン

    PRESERVE8

    AREA    SCopy, CODE, READONLY
    EXPORT strcopy
strcopy               ; r0 points to destination string.
                      ; r1 points to source string.
    LDRB r2, [r1],#1  ; Load byte and update address.
    STRB r2, [r0],#1  ; Store byte and update address.
    CMP  r2, #0       ; Check for zero terminator.
    BNE  strcopy      ; Keep going if not.
    BX   lr           ; Return.
    END

Example 5.4 は、strtest.c および scopy.s として、主なサンプルディレクトリの ...\asm にあります。

このサンプルをコマンドラインからビルドするには、以下の手順に従います。

  1. 「armasm --debug scopy.s」と入力し、アセンブリ言語ソースをビルドします。

  2. 「armcc -c --debug strtest.c」と入力し、C ソースをビルドします。

  3. 「armlink strtest.o scopy.o -o strtest」と入力し、オブジェクトファイルをリンクします。

  4. 適切なデバッグターゲットで、互換性のあるデバッガ(例えば、AXD や RealView Debugger)を使用してイメージを実行します。

アセンブリ言語からの C 言語の呼び出し

Example 5.6Example 5.7 では、アセンブリ言語から C 言語を呼び出す方法を示しています。

Example 5.6. C における関数の定義

int g(int a, int b, int c, int d, int e)
{
    return a + b + c + d + e;
}

Example 5.7. アセンブリ言語の呼び出し

    ; int f(int i) { return g(i, 2*i, 3*i, 4*i, 5*i); }

    PRESERVE8

    EXPORT f
    AREA f, CODE, READONLY
    IMPORT g           ; i is in r0
    STR lr, [sp, #-4]! ; preserve lr
    ADD r1, r0, r0     ; compute 2*i (2nd param)
    ADD r2, r1, r0     ; compute 3*i (3rd param)
    ADD r3, r1, r2     ; compute 5*i
    STR r3, [sp, #-4]! ; 5th param on stack
    ADD r3, r1, r1     ; compute 4*i (4th param)
    BL g               ; branch to C function
    ADD sp, sp, #4     ; remove 5th param
    LDR pc, [sp], #4   ; return
    END

C++ 言語からの C 言語の呼び出し

Example 5.8 およびExample 5.9 では、C++ 言語から C 言語を呼び出す方法を示しています。

Example 5.8. C++ 言語からの C 関数の呼び出し

struct S {            // has no base classes
                      // or virtual functions
    S(int s) :i(s) { }
    int i;
};
extern "C" void cfunc(S *);
// declare the C function to be called from C++
int f(){
    S s(2);           // initialize 's'
    cfunc(&s);        // call 'cfunc' so it can change 's'
    return s.i * 3;
}

Example 5.9. C 言語における関数の定義

struct S {
    int i;
};
void cfunc(struct S *p) {
/* the definition of the C function to be called from C++ */
    p->i += 5;
}

C++ 言語からのアセンブリ言語の呼び出し

Example 5.10Example 5.11 では、C++ 言語からアセンブリ言語を呼び出す方法を示しています。

Example 5.10. C++ 言語からのアセンブリ言語の呼び出し

struct S {        // has no base classes
                  // or virtual functions
    S(int s) :i(s) { }
    int i;
};

extern "C" void asmfunc(S *);   // declare the Asm function
                                // to be called
int f() {
    S s(2);                     // initialize 's'
    asmfunc(&s);                // call 'asmfunc' so it
                                // can change 's'
    return s.i * 3;
}

Example 5.11. アセンブリ言語で記述された関数の定義

    PRESERVE8

    AREA Asm, CODE
    EXPORT asmfunc
asmfunc                ; the definition of the Asm
    LDR r1, [r0]       ; function to be called from C++
    ADD r1, r1, #5
    STR r1, [r0]
    BX  lr
    END

C 言語からの C++ 言語の呼び出し

Example 5.12Example 5.13 では、C 言語から C++ 言語を呼び出す方法を示しています。

Example 5.12. C++ で呼び出される関数の定義

struct S {        // has no base classes or virtual functions
    S(int s) :i(s) { }
    int i;
};

extern "C" void cppfunc(S *p) {
// Definition of the C++ function to be called from C.
// The function is written in C++, only the linkage is C
    p->i += 5;                //
} 

Example 5.13. C 言語での関数の宣言と呼び出し

struct S {
    int i;
};

extern void cppfunc(struct S *p);
/* Declaration of the C++ function to be called from C */

int f(void) {
    struct S s;
    s.i = 2;                /* initialize 's' */
    cppfunc(&s);            /* call 'cppfunc' so it */
                            /* can change 's' */
    return s.i * 3;
}

アセンブリ言語からの C++ 言語の呼び出し

Example 5.14Example 5.15 では、アセンブリ言語から C++ 言語を呼び出す方法を示しています。

Example 5.14. C++ 言語で呼び出される関数の定義

struct S {           // has no base classes or virtual functions
    S(int s) :i(s) { }
    int i;
};
extern "C" void cppfunc(S * p) {
// Definition of the C++ function to be called from ASM.
// The body is C++, only the linkage is C
    p->i += 5;
}

ARM アセンブラ言語では、C++ 関数の名前をインポートし、リンク付き分岐(BL)命令を使用してその関数を呼び出します。

Example 5.15. アセンブリ言語で記述された関数の定義

    AREA Asm, CODE
    IMPORT cppfunc         ; import the name of the C++
                           ; function to be called from Asm

    EXPORT   f
f
    STMFD  sp!,{lr}
    MOV    r0,#2
    STR    r0,[sp,#-4]!    ; initialize struct
    MOV    r0,sp           ; argument is pointer to struct
    BL     cppfunc         ; call 'cppfunc' so it can change
                           ; the struct
    LDR    r0, [sp], #4
    ADD    r0, r0, r0,LSL #1
    LDMFD  sp!,{pc}
    END

C 言語と C++ 言語間での参照の受け渡し

Example 5.16Example 5.17 では、C 言語と C++ 言語の間で参照を受け渡す方法を示しています。

Example 5.16. C++ 関数の定義

extern "C" int cfunc(const int&);
// Declaration of the C function to be called from C++

extern "C" int cppfunc(const int& r) {
// Definition of the C++ to be called from C.
    return 7 * r;
}

int f() {
    int i = 3;
    return cfunc(i);    // passes a pointer to 'i'
}

Example 5.17. C 関数の定義

extern int cppfunc(const int*);
/* declaration of the C++ to be called from C */

int cfunc(const int *p) {
/* definition of the C function to be called from C++ */
    int k = *p + 4;
    return cppfunc(&k);
}

C 言語またはアセンブリ言語からの C++ 言語の呼び出し

Example 5.18Example 5.19、およびExample 5.20 のコードは、C またはアセンブリ言語から C++ 言語の非スタティックな非仮想メンバ関数を呼び出す方法を示しています。関数の符号化された名前を参照するには、コンパイラからアセンブラ出力を使用して下さい。

Example 5.18. C++ メンバ関数の呼び出し

struct T {
    T(int i) :t(i) { }
    int t;
    int f(int i);
};

int T::f(int i) { return i + t; }
// Definition of the C++ function to be called from C.

extern "C" int cfunc(T*);
// declaration of the C function to be called from C++

int f() {
    T t(5);                    // create an object of type T
    return cfunc(&t);
}

Example 5.19. C 関数の定義

struct T;

extern int _ZN1T1fEi(struct T*, int);
    /* the mangled name of the C++ */
    /* function to be called */

int cfunc(struct T* t) {
/* Definition of the C function to be called from C++.*/
    return 3 * _ZN1T1fEi(t, 2);    /* like '3 * t->f(2)' */
}

Example 5.20. アセンブリ言語での関数の実装

    EXPORT cfunc
    AREA foo, CODE
    IMPORT  _ZN1T1fEi

cfunc
    STMFD   sp!,{lr}         ; r0 already contains the object pointer
    MOV r1, #2
    BL _ZN1T1fEi
    ADD r0, r0, r0, LSL #1   ; multiply by 3
    LDMFD sp!,{pc}
    END

別の方法として、Example 5.21 で示すように、Example 5.18Example 5.20 は、組み込みアセンブリを使用して実装できます。このサンプルでは、関数の参照に __cpp キーワードが使用されます。そのため、関数の符号化された名前を把握しておく必要はありません。

Example 5.21. 組み込みアセンブリでの関数の実装

struct T {
    T(int i) :t(i) { }
    int t;
    int f(int i);
};
int T::f(int i) { return i + t; }

// Definition of asm function called from C++
__asm int asm_func(T*) {
    STMFD sp!, {lr}
    MOV r1, #2;
    BL __cpp(T::f);
    ADD r0, r0, r0, LSL #1 ; multiply by 3
    LDMFD sp!, {pc}
}

int f() {
    T t(5); // create an object of type T
    return asm_func(&t);
}
Copyright © 2002-2006 ARM Limited. All rights reserved.ARM DUI 0203GJ
Non-Confidential