【问题标题】:Keep getting e8 00 00 00 00 as the machine code to call a function in assembly继续获取 e8 00 00 00 00 作为机器代码以在汇编中调用函数
【发布时间】:2017-11-25 01:14:13
【问题描述】:

我知道在我的文件中使用 objdump -dr 时,call 在机器代码中显示为 e8 00 00 00 00,因为它尚未链接。但我需要找出链接器完成工作后00 00 00 00 会变成什么。我知道它应该计算偏移量,但我对此有点困惑。

以下面的代码为例,链接器部分完成后,e8 00 00 00 00 应该如何?我如何得到这个答案?

我正在使用此示例代码进行测试:(我正在尝试调用 moo)

Disassembly of section .text:

0000000000000000 <foo>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   89 7d fc                mov    %edi,-0x4(%rbp)
   7:   8b 45 fc                mov    -0x4(%rbp),%eax
   a:   83 e8 0a                sub    $0xa,%eax
   d:   5d                      pop    %rbp
   e:   c3                      retq   

000000000000000f <moo>:
   f:   55                      push   %rbp
  10:   48 89 e5                mov    %rsp,%rbp
  13:   89 7d fc                mov    %edi,-0x4(%rbp)
  16:   b8 01 00 00 00          mov    $0x1,%eax
  1b:   5d                      pop    %rbp
  1c:   c3                      retq   

000000000000001d <main>:
  1d:   55                      push   %rbp
  1e:   48 89 e5                mov    %rsp,%rbp
  21:   48 83 ec 10             sub    $0x10,%rsp
  25:   c7 45 fc 8e 0c 00 00    movl   $0xc8e,-0x4(%rbp)
  2c:   8b 45 fc                mov    -0x4(%rbp),%eax
  2f:   89 c7                   mov    %eax,%edi
  31:   e8 00 00 00 00          callq  36 <main+0x19>
            32: R_X86_64_PC32   moo-0x4
  36:   89 45 fc                mov    %eax,-0x4(%rbp)
  39:   b8 00 00 00 00          mov    $0x0,%eax
  3e:   c9                      leaveq 
  3f:   c3                      retq

【问题讨论】:

    标签: assembly linker x86 disassembly machine-code


    【解决方案1】:

    我所知道的几种架构上的目标文件和可执行文件不一定必须在链接时修复跳转目标。

    这是一个提供灵活性的功能。

    跳转目标地址不必必须在指令执行之前固定。它们不需要在链接时修复——甚至在程序启动时也不需要!

    大多数系统(Windows、Linux、Unix、VAX/VMS)将目标代码中的此类位置标记为需要调整的地址。还有关于目标地址是什么、它是什么类型的引用的附加信息(例如绝对或相对;16 位、24 位、32 位、64 位等)。

    那里的零值不一定是占位符,而是评估结果的基值。例如,如果指令(无论出于何种原因)为call 5+external_address,则目标代码中可能存在5 (e8 05 00 00 00)。

    如果您想在执行时查看地址是什么,请在调试器下运行程序,在该指令处放置一个断点,然后在指令执行前查看该指令。


    一种称为 ASLR (address space layout randomization) 的常见防病毒、安全增强功能会故意将程序部分加载到不一致的地址,以阻止恶意代码更改程序或数据。在此环境中运行的程序可能没有分配一些目标地址,直到程序运行一段时间之后。

    (与此相关的是,VAX/VMS 特别具有复杂的固定模式,其中一个方程描述了计算一个值所需的操作。操作包括加法、减法、乘法、除法、移位、旋转,可能还有其他。我从未见过它实际使用过,但思考如何应用该功能很有趣。)

    【讨论】:

      【解决方案2】:

      但你清楚地知道如何做这一切。您知道如何在链接之前反汇编,只需在之后反汇编,看看链接器如何修改这些指令。

      asm(".globl _start; _start: nop\n");
      
      unsigned int foo ( unsigned int x )
      {
          return(x+5);
      }
      unsigned int moo ( unsigned int x )
      {
          return(foo(x)+3);
      }
      
      int main ( void )
      {
          return(moo(3)+2);
      }
      
      0000000000000000 <_start>:
         0:   90                      nop
      
      0000000000000001 <foo>:
         1:   55                      push   %rbp
         2:   48 89 e5                mov    %rsp,%rbp
         5:   89 7d fc                mov    %edi,-0x4(%rbp)
         8:   8b 45 fc                mov    -0x4(%rbp),%eax
         b:   83 c0 05                add    $0x5,%eax
         e:   5d                      pop    %rbp
         f:   c3                      retq   
      
      0000000000000010 <moo>:
        10:   55                      push   %rbp
        11:   48 89 e5                mov    %rsp,%rbp
        14:   48 83 ec 08             sub    $0x8,%rsp
        18:   89 7d fc                mov    %edi,-0x4(%rbp)
        1b:   8b 45 fc                mov    -0x4(%rbp),%eax
        1e:   89 c7                   mov    %eax,%edi
        20:   e8 00 00 00 00          callq  25 <moo+0x15>
        25:   83 c0 03                add    $0x3,%eax
        28:   c9                      leaveq 
        29:   c3                      retq   
      
      000000000000002a <main>:
        2a:   55                      push   %rbp
        2b:   48 89 e5                mov    %rsp,%rbp
        2e:   bf 03 00 00 00          mov    $0x3,%edi
        33:   e8 00 00 00 00          callq  38 <main+0xe>
        38:   83 c0 02                add    $0x2,%eax
        3b:   5d                      pop    %rbp
        3c:   c3                      retq   
      
      
      0000000000001000 <_start>:
          1000:   90                      nop
      
      0000000000001001 <foo>:
          1001:   55                      push   %rbp
          1002:   48 89 e5                mov    %rsp,%rbp
          1005:   89 7d fc                mov    %edi,-0x4(%rbp)
          1008:   8b 45 fc                mov    -0x4(%rbp),%eax
          100b:   83 c0 05                add    $0x5,%eax
          100e:   5d                      pop    %rbp
          100f:   c3                      retq   
      
      0000000000001010 <moo>:
          1010:   55                      push   %rbp
          1011:   48 89 e5                mov    %rsp,%rbp
          1014:   48 83 ec 08             sub    $0x8,%rsp
          1018:   89 7d fc                mov    %edi,-0x4(%rbp)
          101b:   8b 45 fc                mov    -0x4(%rbp),%eax
          101e:   89 c7                   mov    %eax,%edi
          1020:   e8 dc ff ff ff          callq  1001 <foo>
          1025:   83 c0 03                add    $0x3,%eax
          1028:   c9                      leaveq 
          1029:   c3                      retq   
      
      000000000000102a <main>:
          102a:   55                      push   %rbp
          102b:   48 89 e5                mov    %rsp,%rbp
          102e:   bf 03 00 00 00          mov    $0x3,%edi
          1033:   e8 d8 ff ff ff          callq  1010 <moo>
          1038:   83 c0 02                add    $0x2,%eax
          103b:   5d                      pop    %rbp
          103c:   c3                      retq   
      

      例如

      20:   e8 00 00 00 00        callq  25 <moo+0x15>
      1033: e8 d8 ff ff ff        callq  1010 <moo>
      

      【讨论】:

        【解决方案3】:

        使用objdump -r,您的反汇编打印了重定位-d

          31:   e8 00 00 00 00          callq  36 <main+0x19>
                    32: R_X86_64_PC32   moo-0x4
        

        ld-linux.so.2 loader 将重定位对象(在现代世界中,它甚至会将可执行文件重定位到随机地址)并用正确的地址填充重定位。

        通过在main 处添加断点并启动程序来检查gdb(链接器在main 函数启动之前工作):

        gdb ./program
        (gdb) start
        (gdb) disassemble main
        

        如果您想在不重定位的情况下编译代码,请显示源代码和编译选项。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-09
          • 2019-03-26
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多