简体   繁体   English

为什么 MIPS GCC 在 function 调用(GOT 指针)之后从 16($fp)重新加载 28 美元,而没有先存储到 16($fp)?

[英]Why is MIPS GCC reloading $28 from 16($fp) after function calls (a GOT pointer), without having stored to 16($fp) first?

I think I need to paste the full code although it looks long.我想我需要粘贴完整的代码,虽然它看起来很长。

I write a simple code for test.我写了一个简单的代码进行测试。

#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;

}

After assembly:组装后:

    .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"

I realize after each function call, there is a lw $28,16($fp) instruction.我意识到在每个 function 调用之后,都有一条lw $28,16($fp)指令。 But I don't see any code that would have stored a value there first in either the caller or callee.但是我没有看到任何代码会首先在调用者或被调用者中存储一个值。

I can read MIPS assembly.我可以阅读 MIPS 程序集。 I know that lw is load word, and how $fp and $sp are frame pointer and stack pointer.我知道lw是加载字,以及 $fp 和 $sp 是帧指针和堆栈指针。

I just can't understand how it makes sense to load anything from 16($fp) ;我只是不明白从16($fp)加载任何内容有什么意义; it seems there is an uninitialized space.似乎有一个未初始化的空间。

I know $28 is $gp , and can see it being used as a GOT pointer to load function addresses before calls, but it seems nothing initializes that register either before its used in functions.我知道$28$gp ,并且可以看到它被用作 GOT 指针,以在调用之前加载 function 地址,但似乎没有在函数中使用该寄存器之前初始化该寄存器。

Does the MIPS calling convention require $28 to already be pointing at the GOT on function entry? MIPS 调用约定是否需要$28才能指向 function 条目上的 GOT?

lw $28,16($fp)

lw is a "load word" instruction -- it loads a word (4 bytes or 32 bits) from memory into a register. lw是一个“加载字”指令——它将一个字(4 字节或 32 位)从 memory 加载到寄存器中。 $28 is the destination register (also sometimes referred to a $gp ), and 16($fp) is the address to load from -- 16 bytes into the frame ( $fp is the frame pointer register, and 16 is added to it to get the address to load from). $28是目标寄存器(有时也称为$gp ),而16($fp)是要从 16 个字节加载到帧中的地址( $fp是帧指针寄存器,并将 16 添加到它获取要加载的地址)。

The "frame" is generally used to hold local variables of the function --when a function starts, it allocates a frame on the stack by subtracting a constant from $sp , then stores the caller's $fp value somewhere in there and copies $sp to $fp so it points at this newly allocated frame. “帧”通常用于保存 function 的局部变量——当 function 启动时,它通过从$sp中减去一个常量来在堆栈上分配一个帧,然后将调用者的$fp值存储在其中某处并复制$sp$fp所以它指向这个新分配的帧。 It then reads and writes local data into/from the frame with load( l ) and store( s ) instructions.然后,它使用 load( l ) 和 store( s ) 指令将本地数据读取到帧中或从帧中写入本地数据。

If you had compiled with optimization, GCC would keep locals in registers when possible instead of wasting huge numbers of instructions storing/reloading them to the stack.如果您使用优化进行编译,GCC 会尽可能将局部变量保存在寄存器中,而不是浪费大量指令将它们存储/重新加载到堆栈中。 And would access stack memory relative to the stack pointer, instead of spending an instruction to set up $fp as a traditional frame pointer.并且将访问相对于堆栈指针的堆栈 memory,而不是花费一条指令将$fp设置为传统的帧指针。 Un-optimized code doesn't look anything like what a human would write by hand, but optimized code sometimes does.未优化的代码看起来不像人类手写的那样,但优化的代码有时会这样。

I think I know why.我想我知道为什么。

I have ignored the .cprestore 16 automatically because I regard it as useless.我自动忽略了.cprestore 16 ,因为我认为它没用。 But it turns out to emit actual instructions, not just metadata, related to the $gp register.但事实证明,它会发出与$gp寄存器相关的实际指令,而不仅仅是元数据。

.cprestore 16 will expand to sw $gp,16(sp) . .cprestore 16将扩展为sw $gp,16(sp) It is used together with .cpload $25 and other necessary code.它与.cpload $25和其他必要的代码一起使用。 Specifically, you can read the link https://www.linux-mips.org/wiki/PIC_code具体可以阅读链接https://www.linux-mips.org/wiki/PIC_code

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 树莓派半精度浮点上的gcc(binary16,alternative,__ fp16)使用库函数 - gcc on raspberry half precision floating point (binary16, alternative, __fp16) uses library function mips帧指针($ fp)全局指针 - mips frame pointer ($fp) global pointer 如何在g86上为x86_64启用__fp16类型 - How to enable __fp16 type on gcc for x86_64 __fp16 类型在 GNU ARM C++ 中未定义 - __fp16 type undefined in GNU ARM C++ 我应该如何让 gcc 在进入函数的途中将堆栈指针重新对齐到 16 字节边界? - How should I get gcc to realign the stack pointer to a 16-byte boundary on the way in to a function? 在GCC中获取指针的低16位编译时间 - Getting the lower 16 bits of a pointer compile time in GCC 为ARM上的例外设置soft-fp的GCC? - Setting up GCC for soft-fp with exceptions on ARM? ICC 中 -fp-model fast=1 的 GCC/Clang 等价物是什么 - What is GCC/Clang equivalent of -fp-model fast=1 in ICC GCC交叉编译器(用于ARM micro)在没有FP指令的函数上抱怨“不支持的浮点ABI” - GCC cross compiler (for ARM micro) complains about 'non supported floating point ABI' at a function where no FP instruction is present 哪个gcc O2标志可能会导致fp计算失败? - Which gcc O2 flag may cause failure in fp calculation?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM