编译器生成的汇编语句执行顺序为什么与C代码顺序不同

编译器生成的汇编语句执行顺序为什么与C代码顺序不同,第1张

不影响语义的前提下编译器可以任意重排代码顺序;

在乱序执行(Out-of-Order)的CPU里,机器码的执行也可以不按照你在“汇编”层面上看到的顺序执行,只要不影响语义。

所以说这些中间步骤的顺序,作为底层细节平时不需要那么在意——它们多半跟原始源码的顺序是不一样的。

现代优化编译器优化的思路之一是“基于依赖的优化”(dependence-based optimization)。题主引用的CSAPP的例子:

int arith(int x, int y, int z) {

int t1 = x + y

int t2 = z * 48

int t3 = t1 &0xFFFF

int t4 = t2 * t3

return t4

}

所有涉及运算的值都是局部标量变量(local scalar variable),这是最便于编译器做分析的情况,所有依赖都可以显式分析。

由于整个函数没有分支,这里也不需要讨论控制依赖(control dependence),只要讨论数据依赖(data dependence)就好。

把数据依赖图画出来是个DAG(这里正好是棵树,特例了):

xyz48

\ / \ /

t1 0xFFFF t2

\ //

t3/

\ /

t4

优化必须要满足的约束是:每个节点求值之前,其子节点(依赖的数据源)必须要先求了值。

显然,t1和t2之间没有依赖关系,它们的相对求值顺序怎样重排都没关系。

有本我很喜欢的书,里面讲的是各种基于依赖的优化:Optimizing Compilers for Modern Architectures - A Dependence-based Approach

以上是理论部分。

================================================================

下面来看例子。

我们可以用一个实际编译器来看看CSAPP的例子编译出来的结果:

.text

# -- Begin arith

.p2align 4,,15

.globl arith

.type arith, @function

arith:

.p2align 4,,7

/*.L0:*/ /* Block BB[54:2] preds: none, freq: 1.000 */

movl 8(%esp), %edx /* ia32_Load T[139:10] -:1:22 */

addl 4(%esp), %edx /* ia32_Add Iu[141:12] -:2:14 */

movzwl %dx, %edx /* ia32_Conv_I2I Iu[142:13] -:4:15 */

imull 12(%esp), %edx /* ia32_IMul Iu[143:14] -:5:15 */

leal (%edx,%edx,2), %eax /* ia32_Lea Iu[144:15] -:5:15 */

shll $0x4, %eax /* ia32_Shl Iu[146:17] -:5:15 */

ret /* ia32_Return X[152:23] -:6:3 */

.size arith, .-arith

# -- End arith

这里用的是libFirm。可见它跟CSAPP书里所说的汇编的顺序又有所不同。这也是完全合理的。

这个编译结果的顺序是:

edx = y

edx += x

edx = zeroextend dx// edx = edx &0xFFFF

edx *= z

eax = edx * 3

eax <<= 4// eax = eax * 16

也是完全符合依赖关系的约束的一种顺序。

之所以用libFirm举例是因为它的中间表示(Intermediate Representation)是一种程序依赖图(Program Dependence Graph),可以很方便的看出控制与数据依赖。把CSAPP那里例子对应的libFirm IR画出来,是这个样子的:

(这张图跟我前面画的数据依赖图正好是左右翻转的,不过意思一样。(这张图跟我前面画的数据依赖图正好是左右翻转的,不过意思一样。

Arg 0、1、2分别代表x、y、z。白色方块是普通数据节点,黄色方块是常量节点,蓝色方块是内存相关节点,红色方块是控制流节点,粉红色方块是特殊的开始/结束节点。)

某版LLVM生成的代码:

ModuleID = '/tmp/webcompile/_16355_0.bc'

target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"

target triple = "x86_64-ellcc-linux"

Function Attrs: nounwind readnone

define i32 @arith(i32 %x, i32 %y, i32 %z) #0 {

entry:

%add = add nsw i32 %y, %x

%mul = mul nsw i32 %z, 48

%and = and i32 %add, 65535

%mul1 = mul nsw i32 %mul, %and

ret i32 %mul1

}

attributes #0 = { nounwind readnone "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.ident = !{!0}

!0 = !{!"ecc 0.1.10 based on clang version 3.7.0 (trunk) (based on LLVM 3.7.0svn)"}

最终生成的x86汇编:

.text

.file "/tmp/webcompile/_15964_0.c"

.globl arith

.align 16, 0x90

.type arith,@function

arith: # @arith

# BB#0: # %entry

movl 8(%esp), %eax

addl 4(%esp), %eax

movzwl %ax, %eax

imull 12(%esp), %eax

shll $4, %eax

leal (%eax,%eax,2), %eax

retl

.Ltmp0:

.size arith, .Ltmp0-arith

.ident "ecc 0.1.10 based on clang version 3.7.0 (trunk) (based on LLVM 3.7.0svn)"

.section ".note.GNU-stack","",@progbits

GCC 4.9.2 x86-64:

arith(int, int, int):

leal (%rdx,%rdx,2), %eax

addl %edi, %esi

movzwl %si, %esi

sall $4, %eax

imull %esi, %eax

ret

Zing VM Server Compiler x86-64:

# edi: x

# esi: y

# edx: z

movl %edx, %eax

shll $0x4, %eax

leal (%rsi, %rdi, 1), %ecx

shll $0x5, %edx

addl %edx, $eax

movzwl %ecx, %edx

imull %edx, %eax

首先声明是转来的,因为我回答你这个问题带了个网址,就一直提示"敏感"回答不上 0 引言 随着计算机技术的迅速发展,计算机技术应用的领域也逐渐扩大,人们希望计算机这一智能体能够解决各个领域的更多、更复杂的问题,从而也对计算机软件产品的功能、质量、开发成本和时间提出了越来越多的要求,软件技术受到了前所未有的挑战。传统的软件工程主要关注新软件的分析与设计,但随着软件系统的规模和复杂度日益增长,软件的生命周期越来越长,软件开发的很大一部分工作集中于维护和改造现有的软件系统,而这些现有系统的需求、设计决策、业务规则、历史数据等统称为遗产系统(LS,Legacy System),LS是一种巨大的、长期的投资,因为如何充分利用这些有用的资产对新系统的开发显得尤其重要。另一方面,随着Internet技术的普及,Web用户增多,很多软件厂商需要将系统移植到Web上,进一步加剧了对软件维护的需求。实践研究表明,软件资源预算的50%~80%消耗在对现有系统的维护上,而软件维护者理解程序源代码的时间要占整个软件维护的47%~62%。软件维护已经成为软件工程面临的重要课题之一,而正确和全面地理解软件系统是对软件进行维护的前提,软件逆向工程应运而生,成为软件工程领域的一个新兴分支,其目标就是开发帮助人们理解已有软件系统的方法、工具,为软件系统的维护和演化提供支持。 文中主要介绍逆向工程的基本概念、主要步骤、分析方法、研究现状、存在的问题以及发展方向。 1 逆向工程的基本概念 “逆向工程”这个名词最早出现在对硬件产品的分析中,人们分析硬件产品以便改进自己的产品。M.G.Rekoffir将逆向工程定义为:对一个复杂的硬件系统实施有条理的检查,以开发出关于这个系统的一组规范说明的过程。在把这个概念应用到软件系统过程中,研究人员发现利用其中的许多方法可以获得对系统以及系统结构的理解。然而,对一个硬件系统实施逆向工程,一般是为了得到这个系统的复制品,对一个软件系统实施逆向工程,一般是为了获得对这个系统在设计层次上的理解,以便于系统的维护、巩固、移植、改进。 软件逆向工程的基本原理是抽取软件系统的主要部分而隐藏细节,然后使用抽取出的实体在高层上描述软件系统。在软件工程领域,迄今为止没有统一的逆向工程定义,较为通用的是Elliot Chikofsky和Cross1990年定义的逆向工程的相关术语。软件工程通常被认为是开发一个新的系统,尽管软件工程也包括逆向工程和再工程,为了避免对软件工程含义的误解,引进了正向工程的概念。 (1)正向工程(Forward Engineering):从系统的高层抽象和逻辑上独立于实现的设计到系统的物理设计的传统过程,具体地说是从用户的需求到高层设计,再到底层设计,最后到实现的过程。 (2)逆向工程(Reverse Engineering):对系统进行分析,以确定系统的组件和组件之间的相互作用,以其他形式表示系统,或在较高的抽象层次上表示系统的过程。值得说明的是,在对一个系统实施逆向工程时,并不改变这个系统本身,也不包括在此系统上构建新的系统的过程。 (3)重构(Restructuring):保持系统外部行为(功能和语义)的前提下,在统一抽象层次上改变表示形式。 (4)再工程(Reengineering):通过逆向工程、重构和正向工程对现有系统进行审查和改造,将其重组为一种新形式。 (5)设计恢复(Design Recovery):结合目标系统、领域知识和外部消息认定更高层次的抽象。其中,再工程、设计恢复不改变系统,重构改变了系统。但不改变其功能,再工程涉及到正向工程与逆向工程的联合使用,逆向工程解决程序的理解问题,正向工程检验哪些功能需要增加、保留和删除,再工程改变了系统的功能和方向,是最根本和最有深远影响的扩展。 图1显示这些概念之间的关系。 2 主要步骤和分析方法 由逆向工程定义可知:软件逆向工程的任务包括分析系统、抽象系统和展现系统,从而实现协助用户理解系统的目的。 分析系统是指分析系统的结构及运行过程,但不管目标系统面向何种应用领域,分析系统不外乎是分析系统的静态信息和动态信息。目标系统面对不同的应用领域,要实现抽象目标系统的任务,需要领域知识和专家的经验。展现系统最好的方式是使系统可视化。 图1 关系图 现有的逆向工程分析方法主要有以下4种: (1)词法分析和语法分析。 该方法主要是对程序源码进行分析,得到程序信息的多种有用表示,其中最常用的就是交叉引用列表。通过语法分析可以得到两类表示:分析树(parse tree)、抽象语法树AST(abstract syntax tree),其中AST是更复杂的程序分析工具基础,包含了和程序的实际内容相关的细节。 (2)图形化方法。 图形化方法包括控制流分析、数据流分析以及程序依赖图。控制流分析是在确定程序语法结构之后进行。数据流分析关注于解决程序中从定义到使用的过程的相关的问题,比控制流分析要复杂得多。程序依赖图是数据流分析的进一步改进,比数据流分析更复杂。在程序依赖图中,控制流和数据流依赖放在一起处理,程序依赖图还具有这样的结构特性:一个程序依赖图描述了一个控制依赖的区域。 (3)程序切片。 切片技术来源于数据流分析方法,已经成为很多程序理解工具的基础。一个程序切片是由程序中的一些语句和判定表达式组成的集合。这些语句和判定表达式可能会影响在程序的某个位置上所定义或使用的变量的值。利用切片技术可以将关注点确定在一个较小范围而不是关注整个程序。 (4)动态分析。 静态分析是对程序源码进行分析。动态分析则是在程序运行时进行分析,基本方法是对程序进行植入。植入是在一种在全局范围内更改源代码以添加额外 *** 作的过程。这种方法的基本原理是:利用代码的结构信息,依据固定的规则,将软件触发器添加到代码中。 追问: 我问的是具体的方法,不是理论。比如“ 词法分析 和语法分析”,怎么分析,用什么工具? 回答: 你要学下编程了,最起码 汇编 的命令你要知道,如果你连命令是什么意思还怎么分析呢, 分析的软件 ollydbg

错误提示不是说了吗 “请检查指定的 SQL Server 实例是否存在,且服务是否在运行。”

1、检查你本机的 SQL Server 服务是否启动了。

2、检查你有没有这个数据库。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/10980304.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-12
下一篇 2023-05-12

发表评论

登录后才能评论

评论列表(0条)

保存