8

c からアセンブリ関数を呼び出そうとしていますが、エラーが発生し続けます。

    .text
    .globl integrate
    .type integrate, @function
integrate:
    push %ebp
    mov %esp, %ebp
    mov $0,%edi
start_loop:                
    cmp %edi,1024           
    je loop_exit
    mov 8(%ebp),%eax          
    mov 12(%ebp),%ecx          
    sub %eax,%ecx              
    add %edi,%ecx
    incl %edi                
    jmp start_loop             
loop_exit:                 
    movl %ebp, %esp
    popl %ebp
    ret   

これは私のアセンブリ関数で、integrate.s というファイルです。

#include <stdio.h>

extern int integrate(int from,int to);

void main()
{
    printf("%d",integrate(1,10));
}

これが私のCコードです。

function.c:5:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
/tmp/cciR63og.o: In function `main':
function.c:(.text+0x19): undefined reference to `integrate'
collect2: ld returned 1 exit status

gcc -Wall function.c -o 関数を使用してコードをコンパイルしようとすると、「統合への未定義の参照」エラーが発生します。

#include<(file path)/integrate.s>

しかし、それはうまくいきませんでした。ところで、アセンブリコードが何をしているのかは重要ではありません。

4

4 に答える 4

11

コードに次の問題があります。

  • 呼び出し規約の値を保持する必要がありますedi
  • cmp %edi,1024はアドレスとして使用1024されており、おそらく障害が発生します。cmp $1024,%edi即値と比較したい
  • リロードeaxecxており、各反復から引数を使用しているため、実行する計算は効果がありません
  • あなたは賢明な戻り値を入れていないようですeaxfrom渡された値を返します)

最初の 2 点は、「アセンブリ コードが何をしているかが重要ではない」場合でも当てはまります。

于 2012-12-16T13:36:24.740 に答える
5

警告: 「main」の戻り型は「int」ではありません</p>

「main」の戻り値の型が「int」ではないことを意味します... に変更してからint、次のようにします。

int main()
{
}

また、リンカ エラーを解決するには、GCC を次のように呼び出します。

gcc -o myprog main.c integrate.s

そしてそれはうまくいくはずです。

于 2012-12-16T12:28:48.650 に答える
5

x86-64 Linux の例

を呼び出す方法を示す回答が既にここにありますがvoid func(void)、これはパラメーターを受け入れ、質問で尋ねられた戻り値を持つx86-64 Linux の例です。(質問と他のいくつかの回答は、異なる呼び出し規約を持つ32ビットコードを使用しています)。

まず、アセンブリ関数を単純化しましょう。

# Need to make it global so it can be accessed in another file with extern
.globl integrate

# Cannot hurt to define it as a function type, sometimes useful for dynamic linking, see comments in: https://stackoverflow.com/questions/65837016/how-to-call-a-function-in-an-external-assembly-file#comment116408928_65837016 
.type integrate, @function

integrate:
    # int integrate(int from /*EDI*/,  int to /*ESI*/)
    # INPUT:
    #   the first parameter `from` is contained in %edi, the int-sized low half of %rdi
    #   the second parameter `to`  is contained in %esi
    # OUTPUT:
    #   return is passed in %eax;  
    #      you can leave garbage in the high half of RAX if convenient

    lea  123(%rdi, %rsi), %ecx         # from + to + 123 just for example
    # (main work of function done)

    mov %ecx, %eax # it seems your return value is in %ecx
                   # but we need it in %eax for the return value to C
     # or just use EAX instead of ECX in the first place to avoid this instruction
    ret

これはSystem V呼び出し規則を使用しており、関数の戻り値が渡されrax、関数が受け取るパラメーターが , , , , に渡されrdi、次に逆の順序でスタックに渡されます。( i386 および x86-64 での UNIX および Linux システム コール (およびユーザー空間関数) の呼び出し規則は何ですか)。例えば:rsirdxrcxr8r9

long add_four_nums(int first, long second, short third, unsigned fourth);

このプロトタイプで宣言された関数は、 firstin %edisecondin %rsithirdin %dx、およびfourthinを受け取り%ecxます。で返さresult%raxます。

アセンブリが作成されたので (ただし、関数は主に、引数を受け入れて値を返す方法を示すスタブです)、現在のように C ファイルでその関数を使用できます。

#include <stdio.h>
extern int integrate(int from,int to);
int main() {
    printf("%d\n", integrate(1,10));
}

コンパイルして gcc でリンクし、次のように実行できます。

$ gcc -o combined -Wall main.c integrate.s   && ./combined
于 2021-01-22T05:14:27.813 に答える