- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个简单的 C 程序,可以为函数 func
生成这个 x86-64 程序集。
#include <stdio.h>
#include <string.h>
void func(char *name)
{
char buf[90];
strcpy(buf, name);
printf("Welcome %s\n", buf);
}
int main(int argc, char *argv[])
{
func(argv[1]);
return 0;
}
所以我认为这个
0x000000000000118d <+4>: push %rbp
像放置参数一样推送基指针,即 char *name
然后0x000000000000118e <+5>: mov %rsp,%rbp
将堆栈指针设置为我相信上面的基指针,这使得堆栈指针指向 char *name
此时
然后
0x0000000000001191 <+8>: add $0xffffffffffffff80,%rsp
我对此有点不确定。为什么是0xffffffffffffff80
添加到 rsp 中?这条指令的重点是什么?谁能告诉一下吗?
然后在下一条指令中 0x0000000000001195 <+12>: mov %rdi,-0x78(%rbp)
它只是将十进制 -128 设置为 rdi 。但仍然没有缓冲char buf[90]
可以看到,我的缓冲区在哪里?在接下来的 session 中,有人能告诉我吗?
这行又是什么0x00000000000011a2 <+25>: mov %rax,-0x8(%rbp)
Dump of assembler code for function func:
0x0000000000001189 <+0>: endbr64
0x000000000000118d <+4>: push %rbp
0x000000000000118e <+5>: mov %rsp,%rbp
0x0000000000001191 <+8>: add $0xffffffffffffff80,%rsp
0x0000000000001195 <+12>: mov %rdi,-0x78(%rbp)
0x0000000000001199 <+16>: mov %fs:0x28,%rax
0x00000000000011a2 <+25>: mov %rax,-0x8(%rbp)
0x00000000000011a6 <+29>: xor %eax,%eax
0x00000000000011a8 <+31>: mov -0x78(%rbp),%rdx
0x00000000000011ac <+35>: lea -0x70(%rbp),%rax
0x00000000000011b0 <+39>: mov %rdx,%rsi
0x00000000000011b3 <+42>: mov %rax,%rdi
0x00000000000011b6 <+45>: call 0x1070 <strcpy@plt>
0x00000000000011bb <+50>: lea -0x70(%rbp),%rax
0x00000000000011bf <+54>: mov %rax,%rsi
0x00000000000011c2 <+57>: lea 0xe3b(%rip),%rax # 0x2004
0x00000000000011c9 <+64>: mov %rax,%rdi
0x00000000000011cc <+67>: mov $0x0,%eax
0x00000000000011d1 <+72>: call 0x1090 <printf@plt>
0x00000000000011d6 <+77>: nop
0x00000000000011d7 <+78>: mov -0x8(%rbp),%rax
0x00000000000011db <+82>: sub %fs:0x28,%rax
0x00000000000011e4 <+91>: je 0x11eb <func+98>
0x00000000000011e6 <+93>: call 0x1080 <__stack_chk_fail@plt>
0x00000000000011eb <+98>: leave
0x00000000000011ec <+99>: ret
End of assembler dump.
此外,在上面的汇编中使用 fs 寄存器该指令实际上在做什么 0x0000000000001199 <+16>: mov %fs:0x28,%rax
最佳答案
正如评论中已经提到的,您的缓冲区位于堆栈上。在函数的开头,rsp
会减少以允许更多空间(堆栈向较低地址增长,因此 rsp
随着堆栈的增长而减少)。这个空间通常用于局部变量、传递给函数的参数,也用于其他目的(将在下面讨论)。在您的情况下,您可以通过查看传递给 strcpy
的参数来追溯缓冲区 buf
的位置 - 第一个参数在 rdi
中传递code> 注册,第二个 - 在 rsi
中。
0x00000000000011b0 <+39>: mov %rdx,%rsi
0x00000000000011b3 <+42>: mov %rax,%rdi
0x00000000000011b6 <+45>: call 0x1070 <strcpy@plt>
在上面的代码片段中,您可以看到指向 buf
的指针(strcpy 的第一个参数)在放入 rdi
之前位于 rax
中>。 rax
从这条指令中获取了它的值:
0x00000000000011ac <+35>: lea -0x70(%rbp),%rax
这意味着“加载位于 rbp
指向的地址偏移量 -0x70 处的有效地址(即指针)”。 rbp
指向堆栈指针在函数开头的位置(函数帧指针)。
所以它回答了编译器将缓冲区放置在哪里。
现在还有其他问题:
then in next instruction 0x0000000000001195 <+12>:mov %rdi,-0x78(%rbp) its just setting -128 decimal to rdi.
正如我们所说,rdi
保存函数的第一个参数。这里它保存了func()
的第一个参数,它是一个指向name
的指针。该指令将此参数放入堆栈中,距 rbp
的偏移量为 -0x78 - 8 个字节,位于为缓冲区 buf
保留的空间之前。
最后两个问题是相关的:
also what this line 0x00000000000011a2 <+25>: mov %rax,-0x8(%rbp)
和
also what in above assembly the use of fs register what this instruction actually doing 0x0000000000001199 <+16>: mov %fs:0x28,%rax
0x0000000000001199 <+16>: mov %fs:0x28,%rax
0x00000000000011a2 <+25>: mov %rax,-0x8(%rbp)
...
...
0x00000000000011d7 <+78>: mov -0x8(%rbp),%rax
0x00000000000011db <+82>: sub %fs:0x28,%rax
0x00000000000011e4 <+91>: je 0x11eb <func+98>
0x00000000000011e6 <+93>: call 0x1080 <__stack_chk_fail@plt>
0x00000000000011eb <+98>: leave
在 %fs:0x28
处有一些值(表示 fs
段中的偏移量 0x28)。并且该值被放置(通过rax
)到堆栈中。到为函数分配的空间中的前 8 个字节。它会留在那里,希望不受影响,直到函数即将返回。在那里,它检查堆栈上的值是否已更改。如果它保持不变,跳转(je
)将带您到leave
并且函数将返回。如果堆栈上的值万一发生了更改 - 您的代码导致了堆栈溢出(啊哈!),并且将触发对 __stack_chk_fail 的调用,这可能会警告您有关溢出的信息,也许还可以转储一些调试信息。因此 %fs:0x28
处的值是一种独特的魔法/金丝雀值。
最后一件事 - 关于为什么使用 add $0xffffffffffffff80,%rsp
来分配堆栈空间,而不是 sub
- 其他编译器确实使用 sub
与 GCC 一样(版本 8.5.0 20210514):
sub $0x70,%rsp
分配的资源较少,原因之一是编译器没有为堆栈溢出检查预留空间。
关于c - 通过函数调用了解简单 C 程序的 x86-64 汇编,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71061184/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!