相关疑难解决方法(0)

C语言中的功能序言与结语

我知道嵌套函数调用中的数据会转到堆栈.堆栈本身实现了一个逐步的方法,用于在函数被调用或返回时从堆栈中存储和检索数据.这些方法的名称大多称为Prologue和结语.

我试图搜索关于这个主题的材料没有成功.你们知道关于函数序言和结语如何在C中起作用的任何资源(网站,视频,文章)吗?或者,如果你能解释会更好.

PS:我只是想要一些一般的观点,不是太详细.

c c++

11
推荐指数
1
解决办法
2万
查看次数

为什么 GCC 在堆栈上分配的空间超出了必要的空间,超出了对齐所需的空间?

我正在阅读一本教科书,其中显示了基于 C 代码的汇编代码:

代码:

void echo()
{
   char buf[8];
   otherFunction(buf);
}
Run Code Online (Sandbox Code Playgroud)

汇编代码:

echo:
   subq $24, %rsp      //Allocate 24 bytes on stack, but why allocate 24 instead of 8 bytes?
   movq %rsp, %rdi     //Compute buf as %rsp
   call otherFunction  
Run Code Online (Sandbox Code Playgroud)

我不明白为什么堆栈指针%rsp会减少 24 个字节。我只将 8 个字节的缓冲区分配为char buf[8];,并且没有被调用者保存的寄存器压入堆栈,指令不应该是

subq $8, %rsp
Run Code Online (Sandbox Code Playgroud)

c assembly gcc callstack x86-64

9
推荐指数
2
解决办法
362
查看次数

Tiny C Compiler生成的代码会发出额外的(不必要的?)NOP和JMP

有人可以解释为什么这个代码:

#include <stdio.h>

int main()
{
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

当使用tcc使用tcc编译时,生成这个asm:

00401000  |.  55               PUSH EBP
00401001  |.  89E5             MOV EBP,ESP
00401003  |.  81EC 00000000    SUB ESP,0
00401009  |.  90               NOP
0040100A  |.  B8 00000000      MOV EAX,0
0040100F  |.  E9 00000000      JMP fmt_vuln1.00401014
00401014  |.  C9               LEAVE
00401015  |.  C3               RETN
Run Code Online (Sandbox Code Playgroud)

我猜可能是

00401009  |.  90   NOP
Run Code Online (Sandbox Code Playgroud)

也许有一些内存对齐,但是怎么样

0040100F  |.  E9 00000000     JMP fmt_vuln1.00401014
00401014  |.  C9              LEAVE
Run Code Online (Sandbox Code Playgroud)

我的意思是为什么编译器会插入跳转到下一条指令的近跳转,LEAVE会执行呢?

我在64位Windows上使用TCC 0.9.26生成32位可执行文件.

c x86 assembly tcc compiler-optimization

7
推荐指数
2
解决办法
525
查看次数

为什么在这个函数序言中没有"sub rsp"指令,为什么函数参数存储在负rbp偏移量?

这就是我通过阅读一些内存分段文档所理解的:当调用一个函数时,有一些指令(称为函数序言)将帧指针保存在堆栈上,将堆栈指针的值复制到基本指针中并保存一些局部变量的内存.

这是我尝试使用GDB调试的一个简单代码:

void test_function(int a, int b, int c, int d) {
    int flag;
    char buffer[10];

    flag = 31337;
    buffer[0] = 'A';
}

int main() {
    test_function(1, 2, 3, 4);
}
Run Code Online (Sandbox Code Playgroud)

调试此代码的目的是了解调用函数时堆栈中发生的情况:因此我必须在执行程序的各个步骤(在调用函数之前和执行期间)检查内存.虽然我设法通过检查基指针来查看返回地址和保存的帧指针之类的东西,但我真的无法理解在反汇编代码之后我要写的内容.

拆解:

(gdb) disassemble main
Dump of assembler code for function main:
   0x0000000000400509 <+0>: push   rbp
   0x000000000040050a <+1>: mov    rbp,rsp
   0x000000000040050d <+4>: mov    ecx,0x4
   0x0000000000400512 <+9>: mov    edx,0x3
   0x0000000000400517 <+14>:    mov    esi,0x2
   0x000000000040051c <+19>:    mov    edi,0x1
   0x0000000000400521 <+24>:    call   0x4004ec <test_function>
   0x0000000000400526 <+29>:    pop    rbp
   0x0000000000400527 <+30>:    ret    
End …
Run Code Online (Sandbox Code Playgroud)

c assembly stack x86-64 red-zone

5
推荐指数
1
解决办法
1311
查看次数

阴影空间示例

编辑:

我在下面接受了一个答案,并在代码的最终修订版中添加了自己的答案。希望它能向人们展示阴影空间分配的实际示例,而不是更多的单词。

编辑2:我还设法在(所有内容的)YouTube视频的注释中找到了调用约定PDF的链接,该链接在Shadow Space和Linux的Red Zone上有一些有趣的花絮。可以在这里找到:http : //www.agner.org/optimize/calling_conventions.pdf

原版的:

我在这里和整个Internet上都看过其他几个问题,但是当在64位Windows程序集中调用子例程/ Windows API时,似乎找不到合适的分配“影子空间”的示例。

我的理解是:

  • 来电者应sub rsp,<bytes here>call callee
  • 被调用方应使用它来存储寄存器(如果需要)(或局部变量,如果不需要保存寄存器)
  • 呼叫者将其清除,例如: add rsp,<bytes here>
  • 分配的数量应与32个字节对​​齐

考虑到这一点,这就是我尝试过的方法:

section .text

start:

    sub rsp,0x20 ; <---- Allocate 32 bytes of "Shadow space"

    mov rcx,msg1
    mov rdx,msg1.len
    call write

    add rsp,0x20

    mov rcx,NULL
    call ExitProcess

    ret

write:

    mov [rsp+0x08],rcx      ; <-- use the Shadow space
    mov [rsp+0x10],rdx      ; <-- and again

    mov rcx,STD_OUTPUT_HANDLE   ; Get handle to StdOut
    call GetStdHandle

    mov rcx,rax         ; …
Run Code Online (Sandbox Code Playgroud)

windows 64-bit assembly nasm

5
推荐指数
1
解决办法
1220
查看次数

标签 统计

assembly ×4

c ×4

x86-64 ×2

64-bit ×1

c++ ×1

callstack ×1

compiler-optimization ×1

gcc ×1

nasm ×1

red-zone ×1

stack ×1

tcc ×1

windows ×1

x86 ×1