1

長く見えますが、コード全体を貼り付ける必要があると思います。

テスト用の簡単なコードを書きます。

#include <stdio.h>

int funadd(int a, int b){
  int x = 0;

  x = a + b;

  return x;
}

int fun(int a, int b){
  int y = 17;
  int returnvalue = 0;

  returnvalue = funadd(a, b);
  returnvalue = returnvalue - y;

  return returnvalue;
}

int main(){

  int a = 32;
  int b = 24;

  int c = 0;

  c = fun(a, b);

  printf("%d\n", c);

  return c;

}

組み立て後:

    .file   1 "testfuncall.c"
    .section .mdebug.abi32
    .previous
    .nan    legacy
    .module fp=xx
    .module nooddspreg
    .abicalls
    .text
    .align  2
    .globl  funadd
    .set    nomips16
    .set    nomicromips
    .ent    funadd
    .type   funadd, @function
funadd:
    .frame  $fp,24,$31      # vars= 8, regs= 1/0, args= 0, gp= 8
    .mask   0x40000000,-4
    .fmask  0x00000000,0
    .set    noreorder
    .set    nomacro
    addiu   $sp,$sp,-24
    sw  $fp,20($sp)
    move    $fp,$sp
    sw  $4,24($fp)
    sw  $5,28($fp)
    sw  $0,8($fp)
    lw  $3,24($fp)
    lw  $2,28($fp)
    addu    $2,$3,$2
    sw  $2,8($fp)
    lw  $2,8($fp)
    move    $sp,$fp
    lw  $fp,20($sp)
    addiu   $sp,$sp,24
    jr  $31
    nop

    .set    macro
    .set    reorder
    .end    funadd
    .size   funadd, .-funadd
    .align  2
    .globl  fun
    .set    nomips16
    .set    nomicromips
    .ent    fun
    .type   fun, @function
fun:
    .frame  $fp,40,$31      # vars= 8, regs= 2/0, args= 16, gp= 8
    .mask   0xc0000000,-4
    .fmask  0x00000000,0
    .set    noreorder
    .cpload $25
    .set    nomacro
    addiu   $sp,$sp,-40
    sw  $31,36($sp)
    sw  $fp,32($sp)
    move    $fp,$sp
    .cprestore  16
    sw  $4,40($fp)
    sw  $5,44($fp)
    li  $2,17           # 0x11
    sw  $2,24($fp)
    sw  $0,28($fp)
    lw  $5,44($fp)
    lw  $4,40($fp)
    lw  $2,%got(funadd)($28)
    move    $25,$2
    .reloc  1f,R_MIPS_JALR,funadd
1:  jalr    $25
    nop

    lw  $28,16($fp)
    sw  $2,28($fp)
    lw  $3,28($fp)
    lw  $2,24($fp)
    subu    $2,$3,$2
    sw  $2,28($fp)
    lw  $2,28($fp)
    move    $sp,$fp
    lw  $31,36($sp)
    lw  $fp,32($sp)
    addiu   $sp,$sp,40
    jr  $31
    nop

    .set    macro
    .set    reorder
    .end    fun
    .size   fun, .-fun
    .rdata
    .align  2
$LC0:
    .ascii  "%d\012\000"
    .text
    .align  2
    .globl  main
    .set    nomips16
    .set    nomicromips
    .ent    main
    .type   main, @function
main:
    .frame  $fp,48,$31      # vars= 16, regs= 2/0, args= 16, gp= 8
    .mask   0xc0000000,-4
    .fmask  0x00000000,0
    .set    noreorder
    .cpload $25
    .set    nomacro
    addiu   $sp,$sp,-48
    sw  $31,44($sp)
    sw  $fp,40($sp)
    move    $fp,$sp
    .cprestore  16
    li  $2,32           # 0x20
    sw  $2,24($fp)
    li  $2,24           # 0x18
    sw  $2,28($fp)
    sw  $0,32($fp)
    lw  $5,28($fp)
    lw  $4,24($fp)
    lw  $2,%got(fun)($28)
    move    $25,$2
    .reloc  1f,R_MIPS_JALR,fun
1:  jalr    $25
    nop

    lw  $28,16($fp)
    sw  $2,32($fp)
    lw  $5,32($fp)
    lw  $2,%got($LC0)($28)
    addiu   $4,$2,%lo($LC0)
    lw  $2,%call16(printf)($28)
    move    $25,$2
    .reloc  1f,R_MIPS_JALR,printf
1:  jalr    $25
    nop

    lw  $28,16($fp)
    lw  $2,32($fp)
    move    $sp,$fp
    lw  $31,44($sp)
    lw  $fp,40($sp)
    addiu   $sp,$sp,48
    jr  $31
    nop

    .set    macro
    .set    reorder
    .end    main
    .size   main, .-main
    .ident  "GCC: (Debian 6.3.0-18+deb9u1) 6.3.0 20170516"

各関数呼び出しの後に、lw $28,16($fp)命令があることに気付きました。しかし、呼び出し元または呼び出し先のいずれかに最初に値を格納するコードは見当たりません。

MIPS アセンブリを読み取ることができます。lwそれがロード ワードであり、$fp と $sp がフレーム ポインターとスタック ポインターであることはわかっています。

から何かをロードすることがどのように理にかなっているのか理解できません16($fp)。初期化されていないスペースがあるようです。

私は知って$28おり$gp、呼び出しの前に関数アドレスをロードするためのGOTポインターとして使用されていることがわかりますが、関数で使用される前にそのレジスタを初期化するものは何もないようです。

MIPS 呼び出し規則$28では、関数のエントリで GOT を既に指している必要がありますか?

4

2 に答える 2

2
lw $28,16($fp)

lw「ロードワード」命令です。メモリからレジスタにワード(4バイトまたは32ビット)をロードします。 $28はデスティネーション レジスタ ( a とも呼ばれる$gp) で、16($fp)はロード元のアドレスです。フレームへの 16 バイト ($fpはフレーム ポインタ レジスタで、ロード元のアドレスを取得するために 16 が加算されます)。

「フレーム」は通常、関数のローカル変数を保持するために使用されます。関数が開始すると、 から定数を減算してスタックにフレームを割り当て、$sp呼び出し元の$fp値をそこのどこかに格納してにコピー$sp$fp、これを指すようにします。新しく割り当てられたフレーム。l次に、load( ) および store( s) 命令を使用して、ローカル データをフレームに読み書きします。

最適化を使用してコンパイルした場合、GCC はローカルをスタックに格納/再ロードする膨大な数の命令を無駄にする代わりに、可能な場合はレジスタに保持します。$fpまた、従来のフレーム ポインターとしてセットアップする命令を費やす代わりに、スタック ポインターに関連するスタック メモリにアクセスします。最適化されていないコードは、人間が手作業で書いたものとはまったく異なりますが、最適化されたコードは時々そうなります。

于 2020-04-05T03:50:39.187 に答える