首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >理解和分析装配代码

理解和分析装配代码
EN

Stack Overflow用户
提问于 2018-12-30 22:34:17
回答 2查看 279关注 0票数 3

有人能帮我理解这个汇编代码吗?我对汇编语言完全陌生,我就是搞不懂.下列程序集代码应产生此功能:

函数(Int a) {返回a* 34 }

这些评论//是我的想法,如果我错了,请纠正我

代码语言:javascript
复制
//esp = stack-pointer, ebp = callee saved, eax = return value

pushl %ebp                   // a is pushed on stack
movl %esp,%ebp               // a = stackpointer
movl 8(%ebp),%eax            // eax = M(8 + a).But what is in M(8 + a)?
sall $4,%eax                 // eax << 4
addl 8(%ebp),%eax            // eax = M(8 + a)
addl %eax,%eax               // eax = eax + eax
movl %ebp,%esp               // eax = t
popl %ebp                    // pop a from stack
ret

谁能给我解释一下怎么弄明白吗?非常感谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-12-30 22:54:40

代码语言:javascript
复制
pushl %ebp                   // a is pushed on stack
movl %esp,%ebp               // a = stackpointer

正如在评论中所指出的,ebpa无关。ebp是堆栈基指针--这段代码将ebp的旧值保存到堆栈中,然后将堆栈指针保存在ebp中。

代码语言:javascript
复制
movl 8(%ebp),%eax            // eax = M(8 + a).But what is in M(8 + a)?

对,是这样。堆栈上的是eax的输入值。

代码语言:javascript
复制
sall $4,%eax                 // eax << 4

对,是这样。(结果被分配回eax。)

代码语言:javascript
复制
addl 8(%ebp),%eax            // eax = M(8 + a)

不,你误会了。这将8(ebp)堆栈上的值--即a的原始值--添加到eax。加法应用于值,而不是内存地址。

代码语言:javascript
复制
addl %eax,%eax               // eax = eax + eax

对,是这样。eax的值在这里之后不会被修改,所以这是函数的返回值。

代码语言:javascript
复制
movl %ebp,%esp               // eax = t
popl %ebp                    // pop a from stack
ret

此代码反转前两个指令的效果。这是一个标准的清理序列,与a无关。

这一职能的重要部分可概括为:

代码语言:javascript
复制
a1 = a << 4;   // = a * 16
a2 = a1 + a;   // = a * 17
a3 = a2 + a2;  // = a * 34
return a3;
票数 7
EN

Stack Overflow用户

发布于 2018-12-31 07:12:16

这是非优化代码,因为您使用-O0编译(编译速度快,跳过大多数优化传递)。遗留的堆栈帧设置/清理只是噪音。arg位于堆栈上,位于返回地址的正上方,即函数输入处的4(%esp)上。(另见如何消除GCC/clang组件输出中的“噪音”?)

令人惊讶的是,除非对旧CPU进行调优,否则编译器使用3条指令进行移位和加法,而不是使用imull $34, 4(%esp), %eax ret,/ / 。2指令是现代gcc和嘎嘎的截止,他们的默认调谐。参见例如如何使用x86中两个连续的leal指令将寄存器乘以37?

但是这可以通过使用LEA的两个指令来完成(不包括mov来复制寄存器);代码会膨胀,因为您编译时没有优化。(或者您调到了一个旧CPU,在那里可能有一些理由可以避免LEA。)

我想你一定是用gcc来做这件事的;禁用其他编译器的优化,总是使用imul来乘以一个非2的幂。但是,我找不到一个gcc版本+选项的戈德波特编译器浏览器,给出了准确的代码。我没试过所有可能的组合。MSVC 19.10 -O2使用与代码相同的算法,包括两次加载a

用gcc5.5编译(这是最新的gcc,它不仅使用imul,甚至在-O0),我们得到了类似于您的代码,但不完全是这样。(相同的操作顺序不同,并且不会从内存中两次加载a )。

代码语言:javascript
复制
# gcc5.5 -m32 -xc -O0 -fverbose-asm -Wall
func:
    pushl   %ebp  #
    movl    %esp, %ebp      #,            # make a stack frame

    movl    8(%ebp), %eax   # a, tmp89    # load a from the stack, first arg is at EBP+8

    addl    %eax, %eax      # tmp91          # a*2
    movl    %eax, %edx      # tmp90, tmp92
    sall    $4, %edx        #, tmp92         # a*2 << 4 = a*32
    addl    %edx, %eax      # tmp92, D.1807  # a*2 + a*32

    popl    %ebp    #                     # clean up the stack frame
    ret

gcc5.5 -m32 -O3 -fverbose-asm上使用与GCC版本相同的优化编译戈德波特编译器浏览器gcc5.5 -m32 -O3 -fverbose-asm,我们得到:

代码语言:javascript
复制
# gcc5.5 -m32 -O3.   Also clang7.0 -m32 -O3 emits the same code
func:
    movl    4(%esp), %eax   # a, a          # load a from the stack
    movl    %eax, %edx      # a, tmp93      # copy it to edx
    sall    $5, %edx        #, tmp93        # edx = a<<5 = a*32
    leal    (%edx,%eax,2), %eax             # eax = edx + eax*2 = a*32 + a*2 = a*34
    ret              # with a*34 in EAX, the return-value reg in this calling convention

使用gcc 6.x或更高版本的,我们得到了这种高效的:在现代英特尔CPU上,具有存储源的imul-immediate仅解码为单个微融合uop,而整数乘在Core2和Ryzen之后仅具有3个周期延迟。(https://agner.org/optimize/)。

代码语言:javascript
复制
# gcc6/7/8 -m32 -O3     default tuning
func:
    imull   $34, 4(%esp), %eax    #, a, tmp89
    ret

但是,对于-mtune=pentium3**,,,奇怪的是,我们没有得到一个LEA**。这看起来像是漏掉的优化。LEA对奔腾3/奔腾-M有一个周期的潜伏期。

代码语言:javascript
复制
# gcc8.2 -O3 -mtune=pentium3 -m32 -xc -fverbose-asm -Wall
func:
    movl    4(%esp), %edx   # a, a
    movl    %edx, %eax      # a, tmp91
    sall    $4, %eax        #, tmp91     # a*16
    addl    %edx, %eax      # a, tmp92   # a*16 + a = a*17
    addl    %eax, %eax      # tmp93      # a*16 * 2 = a*34
    ret

这与您的代码相同,但是使用reg mov而不是从堆栈中重新加载来向shift结果添加a

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53981965

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档