《逆向工程权威指南》—第3章3.3节 GCC的其他特性

3.3 GCC的其他特性
只要C语言代码里使用了字符串型常量(可参照3.1.1节的范例),编译器就会把这个字符串常量置于常量字段,以保证其内容不会发生变化。不过GCC有个有趣的特征:它可能会把字符串拆出来单独使用。

我们来看下面这段程序:

#include <stdio.h>
int f1()
{
         printf ("world\n");
};

int f2()
{
         printf ("hello world\n");
};

int main()
{
         f1();
         f2();
};

多数的C/C++编译器(包括MSVC编译器)会分配出两个直接对应的字符串,不过GCC 4.8.1的编译结果则更为可圈可点。

指令清单3.10 在IDA中观察GCC 4.8.1 的汇编指令

> f1                  proc near

s                   = dword ptr -1Ch

                    sub     esp, 1Ch
                    mov     [esp+1Ch+s], offset s ; "world\n"
                    call    _puts
                    add     esp, 1Ch
                    retn
f1                  endp

f2                  proc near

s                   = dword ptr -1Ch

                    sub     esp, 1Ch
                    mov     [esp+1Ch+s], offset aHello ; "hello "
                    call    _puts
                    add     esp, 1Ch
                    retn
f2                  endp

aHello              db  'hello'
s                   db  'world', 0xa, 0
在```
打印字符串“hello world”的时候,这两个词的指针地址实际上是前后相邻的。在调用puts()函数进行输出时,函数本身不知道它所输出的字符串分为两个部分。实际上我们在汇编指令清单中可以看到,这两个字符串没有被“切实”分开。

在f1()函数调用puts()函数时,它输出字符串“world”和外加结束符(数值为零的1个字节),因为puts()函数并不知道字符串可以和前面的字符串连起来形成新的字符串。
时间: 2024-09-20 06:12:45

《逆向工程权威指南》—第3章3.3节 GCC的其他特性的相关文章

《逆向工程权威指南》—第3章3.节x86

第3章 Hello,world!逆向工程权威指南现在,我们开始演示<C语言编程>一书[1]中著名的程序: #include <stdio.h> int main() { printf("hello, world\n"); return 0; }; 3.1 x863.1.1 MSVC接下来我们将通过下述指令,使用MSVC 2010编译下面这个程序. cl 1.cpp /Fa1.asm其中/Fa选项将使编译器生成汇编指令清单文件(assembly listing f

《逆向工程权威指南》—第1章1.1节指令集架构

第一部分 指令讲解逆向工程权威指南在最初接触C/C++时,我就对程序编译后的汇编指令十分着迷.按照从易到难的顺序,我循序渐进地研究了C/C++语言编译器生成汇编指令的模式.经过日积月累的努力,现在我不仅可以直接阅读x86程序的汇编代码,而且能够在脑海里将其还原成原始的C/C++语句.我相信这是学习逆向工程的有效方法.为了能够帮助他人进行相关研究,我把个人经验整理成册,以待与读者分享. 本书包含大量x86/x64和ARM框架的范例.如果读者熟悉其中某一种框架,可以跳过相关的篇幅. 第1章 CPU简

《逆向工程权威指南》—第2章2.1节x86

第2章 最简函数逆向工程权威指南返回预定常量的函数,已经算得上是最简单的函数了. 本章围绕下列函数进行演示: 指令清单2.1 C/C++ 代码 int f() { return 123; }; 2.1 x86在开启优化功能之后,GCC编译器产生的汇编指令,如下所示. 指令清单2.2 Optimizing GCC/MSVC(汇编输出) f: mov eax, 123 ret MSVC编译的程序和上述指令完全一致. 这个函数仅由两条指令构成:第一条指令把数值123存放在EAX寄存器里:根据函数调用约

《逆向工程权威指南》目录—导读

版权 逆向工程权威指南 • 著 [乌克兰] Dennis Yurichev 译 Archer 安天安全研究与应急处理中心 责任编辑 陈冀康 • 人民邮电出版社出版发行 北京市丰台区成寿寺路11号 邮编 100164 电子邮件 315@ptpress.com.cn 网址 http://www.ptpress.com.cn • 读者服务热线:(010)81055410 反盗版热线:(010)81055315 版权声明 逆向工程权威指南 Simplified Chinese translation c

《Netty 权威指南》样章

声明:本文是<Netty 权威指南>的样章目录,感谢博文视点授权并发编程网站发布样章,禁止以任何形式转载此文. 第 2 章  NIO入门 在本章节,我们分别对JDK的BIO.NIO和JDK1.7最新提供的NIO2.0的使用进行详细说明,通过流程图和代码讲解,让大家体会到随着Java IO类库的不断发展和改进,基于Java的网络编程会变得越来越简单,随着异步IO功能的增强,基于Java NIO开发的网络服务器甚至不逊色于采用C++开发的网络程序. 本章主要内容包括:  传统的同步阻塞式IO编程

《逆向工程权威指南》—第3章3.5节MIPS

3.5 MIPS3.5.1 全局指针Global pointer全局指针是MIPS软件系统的一个重要概念.我们已经知道,每条MIPS指令都是32位的指令,所以单条指令无法容纳32位地址(指针).这种情况下MIPS就得传递一对指令才能使用一个完整的指针.在前文的例子中,GCC在生成文本字符串的地址时,就采用了类似的技术. 从另一方面来说,单条指令确实可以容纳一组由寄存器的符号.有符号的16位偏移量(有符号数).因此任何一条指令都可以构成的表达式,访问某个取值范围为"寄存器−32768"-

《逆向工程权威指南》—第3章3.4节ARM

3.4 ARM 根据我个人的经验,本书将通过以下几个主流的ARM编译器进行演示. 2013年6月版本的Keil编译器. Apple Xcode 4.6.3 IDE (含LLVM-GCC 4.2编译器) .[10] 面向 ARM64的GCC 4.9 (Linaro),其32位的Windows程序可由下述网址下载:http://www. linaro.org/ projects/armv8/. 除非特别标注,否则本书中的ARM程序都是32位ARM程序.在介绍64位的ARM程序时,本书会称其为ARM6

《逆向工程权威指南》—第2章2.2节ARM

2.2 ARMARM模式是什么情况? 指令清单2.3 Optimizing Keil 6/2013 (ARM模式) f PROC MOV r0,#0x7b ; 123 BX lr ENDP ARM程序使用R0寄存器传递函数返回值,所以指令把数值123赋值给R0. ARM程序使用LR寄存器(Link Register)存储函数结束之后的返回地址(RA/ Return Address).x86程序使用"栈"结构存储上述返回地址.可见,BX LR指令的作用是跳转到返回地址,即返回到调用者函数

《逆向工程权威指南》—第2章2.3节MIPS

2.3 MIPS在MIPS指令里,寄存器有两种命名方式.一种是以数字命名($0-$31),另一种则是以伪名称(pseudoname)命名($V0-VA0,依此类推).在GCC编译器生成的汇编指令中,寄存器都采用数字方式命名. 指令清单2.4 Optimizing GCC 4.4.5(汇编输出) j $31 li $2,123 # 0x7b 然而IDA则会显示寄存器的伪名称. 指令清单2.5 Optimizing GCC 4.4.5(IDA) jr $ra li $v0, 0x7B 根据伪名称和寄

《逆向工程权威指南》—第3章3.2节x86-64

**3.2 x86-643.2.1 MSVC-x86-64**若用64位MSVC编译上述程序,则会得到下述指令. 指令清单3.7 MSVC 2012 x64 $SG2989 DB 'hello, world', 00H main PROC sub rsp, 40 lea rcx, OFFSET FLAT:$SG2989 call printf xor eax, eax add rsp, 40 ret 0 main ENDP 在x86-64框架的CPU里,所有的物理寄存器都被扩展为64位寄存器.程