-fno-builtin 到底在做啥?

Posted

技术标签:

【中文标题】-fno-builtin 到底在做啥?【英文标题】:What exactly is -fno-builtin doing here?-fno-builtin 到底在做什么? 【发布时间】:2019-06-14 08:38:06 【问题描述】:

所以我正在阅读 Hacking the Art of Exploitation,在书中,他们在 C 代码中使用了 strcpy() 函数:

1   #include <stdio.h>
2   #include <string.h>
3   
4       int main() 
5           char str_a[20];
6   
7           strcpy(str_a, "Hello, world!\n");
8           printf(str_a);
9       

然后他们继续编译源代码并使用gdb 对其进行分析。他在第 6 行、strcpy 函数和第 8 行设置了一个断点,但是当在strcpy 上设置一个断点时,它的内容如下:

(gdb) break strcpy
Function "strcpy" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y

我知道这是因为该库尚未加载,所以它询问他是否要将其作为挂起的断点。然后他运行程序并继续通过断点:

对他来说一切都很好,但是当我尝试在我的计算机上重新创建它时,我得到以下信息:

frinto@kali:~/Documents/theclang/programs/helloworld$ gcc -m32 -g -o char_array char_array.c 
frinto@kali:~/Documents/theclang/programs/helloworld$ gdb -q char_array
Reading symbols from char_array...done.
(gdb) list
1   #include <stdio.h>
2   #include <string.h>
3   
4       int main() 
5           char str_a[20];
6   
7           strcpy(str_a, "Hello, world!\n");
8           printf(str_a);
9       
(gdb) break 6
Breakpoint 1 at 0x11b6: file char_array.c, line 6.
(gdb) break strcpy
Function "strcpy" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 2 (strcpy) pending.
(gdb) break 8
Breakpoint 3 at 0x11d7: file char_array.c, line 8.
(gdb) run
Starting program: /home/frinto/Documents/theclang/programs/helloworld/char_array 

Breakpoint 1, main () at char_array.c:7
7           strcpy(str_a, "Hello, world!\n");
(gdb) cont
Continuing.

Breakpoint 3, main () at char_array.c:8
8           printf(str_a);
(gdb) cont
Continuing.
Hello, world!
[Inferior 1 (process 4021) exited normally]
(gdb) 

注意它是如何完全跳过strcpy 断点的?好吧,我问我的一个朋友这里有什么问题,他告诉我编译时我错过了-fno-builtin 的论点。我对这个参数做了一些最小的谷歌搜索,我真正理解的是它可以让你在内置函数上设置断点。所以我用-fno-builtin 参数编译了程序,然后尝试重新创建它:

frinto@kali:~/Documents/theclang/programs/helloworld$ gcc -m32 -fno-builtin -g -o char_array char_array.c 
frinto@kali:~/Documents/theclang/programs/helloworld$ gdb -q char_array
Reading symbols from char_array...done.
(gdb) list
1   #include <stdio.h>
2   #include <string.h>
3   
4       int main() 
5           char str_a[20];
6   
7           strcpy(str_a, "Hello, world!\n");
8           printf(str_a);
9       
(gdb) break 6
Breakpoint 1 at 0x11c6: file char_array.c, line 6.
(gdb) break strcpy
Breakpoint 2 at 0x1040
(gdb) break 8
Breakpoint 3 at 0x11dc: file char_array.c, line 8.
(gdb) run
Starting program: /home/frinto/Documents/theclang/programs/helloworld/char_array 

Breakpoint 1, main () at char_array.c:7
7           strcpy(str_a, "Hello, world!\n");
(gdb) cont
Continuing.

Breakpoint 2, 0xf7e510b0 in ?? () from /lib/i386-linux-gnu/libc.so.6
(gdb) cont
Continuing.

Breakpoint 3, main () at char_array.c:8
8           printf(str_a);
(gdb) cont
Continuing.
Hello, world!
[Inferior 1 (process 3969) exited normally]
(gdb) 

现在可以了!我有三个问题:

    -fno-builtin 参数到底在做什么? 为什么会显示问号而不是strcpy函数中

Breakpoint 2, 0xf7e510b0 in ?? () from /lib/i386-linux-gnu/libc.so.6

    当我使用-fno-builtin 参数时,为什么它不要求将strcpy 断点设置为挂起?

对不起,长篇大论,我只是想确保一切都被理解。

【问题讨论】:

2.你还没有为你的 libc 安装调试信息。 3.它知道在哪里可以找到strcpy,它不必等待“pending”状态。 【参考方案1】:

来自 man gcc

-fno-builtin
-fno-builtin-function

   Don't recognize built-in functions that do not begin with
   __builtin_ as prefix.  GCC normally generates special code to
   handle certain built-in functions more efficiently; for
   instance, calls to "alloca" may become single instructions
   which adjust the stack directly, and calls to "memcpy" may
   become inline copy loops.  The resulting code is often both
   smaller and faster, but since the function calls no longer
   appear as such, you cannot set a breakpoint on those calls, nor
   can you change the behavior of the functions by linking with a
   different library.  In addition, when a function is recognized
   as a built-in function, GCC may use information about that
   function to warn about problems with calls to that function, or
   to generate more efficient code, even if the resulting code
   still contains calls to that function.  For example, warnings
   are given with -Wformat for bad calls to "printf" when "printf"
   is built in and "strlen" is known not to modify global memory.

   With the -fno-builtin-function option only the built-in
   function function is disabled.  function must not begin with
   __builtin_.  If a function is named that is not built-in in
   this version of GCC, this option is ignored.  There is no
   corresponding -fbuiltin-function option; if you wish to enable
   built-in functions selectively when using -fno-builtin or
   -ffreestanding, you may define macros such as:

           #define abs(n)          __builtin_abs ((n))
           #define strcpy(d, s)    __builtin_strcpy ((d), (s))

function builtins 允许通过内联函数来生成更快的代码,但如手册中所述

you cannot set a breakpoint on those calls

内联函数意味着,不是生成函数调用,而是由编译器直接插入的代码替换其效果。这节省了函数调用并且可以更有效地优化并且通常会导致性能的大幅提升。

但是,代码中不再存在内联函数。调试器断点是通过一些软件陷阱替换特定地址处的指令或使用特定硬件来识别何时到达断点地址来实现的。但由于该函数不再存在,因此没有关联地址,也无法对其进行断点。

挂起断点是在某些代码上设置断点的一种方式,这些代码稍后将由程序动态加载。用-fno-builtinstrcpy直接可用,bp可以直接gdb设置。

请注意,调试需要 -g 标志生成的可执行文件中的特定信息。一般像libc这样的系统库都没有嵌入调试信息,在这些库中输入函数时,gdb通过??提示缺少调试信息。

【讨论】:

您只回答了 OP 提出的 3 个问题中的一个,而且您的回答令人非常不满意——我确信 OP 可以自己阅读手册,但无法理解其含义。 @Employed 俄语 感谢您的建议。我真的不习惯 SO 标准,我同意你的批评。手动输入的很清楚,但是用户可能不知道为什么内联函数不能断点或者库函数为什么不能调试。我相应地更新了答案。【参考方案2】:

-fno-builtin 参数到底在做什么?

-fno-builtin 表示 gcc 不会尝试用内置编译代码替换库函数,并且您不会因为这样的替换而感到任何奇怪。例如,我被puts(mystr) 替换printf("%s", mystr) 所困扰——即使我根本不包括stdio.h

为什么会显示问号而不是strcpy函数

因为没有从源文件或行中获取 strcpy() 的“代码” - gcc 只是插入了某个程序集或其 GIMPLE IR 或其他任何东西,而不是 glibc strcpy() 实现。

当我使用-fno-builtin 参数时,为什么它不要求将 strcpy 断点设置为挂起?

因为此时您处于带有断点的普通普通函数调用的常规情况下,而调试器不必摸不着头脑并考虑要做什么。

【讨论】:

以上是关于-fno-builtin 到底在做啥?的主要内容,如果未能解决你的问题,请参考以下文章

Three.js raycaster 到底在做啥?

Python 多处理模块的 .join() 方法到底在做啥?

MySQL在做啥??启动时 100% 的磁盘利用率

这个条件运算符是做啥的? [复制]

这个函数在做啥

这个@synthesize 语句在做啥?