Understanding disassembled C code: dec %eax and movl $0x0,-0x8(%ebp)

我是研究僧i 提交于 2020-07-09 19:52:17

问题


I'm trying to understand the lines in a piece of disassembled code as shown below. I'd like to know the following:

  • dec %eax : Why is the eax register being decremented? What is the initial value of the eax register?
  • movl $0x0,-0x8(%ebp) : Why are we moving the value 0x0 onto the stack? Doesn't movl store a 32-bit value (4 bytes)? If so, why is the value being stored 8 bytes below the base pointer instead of 4 bytes?

Here's the disassembled binary:

Contents of section .text:
 0000 554889e5 48c745f8 00000000 905dc3    UH..H.E......]. 
Contents of section .rodata:
 0000 48656c6c 6f00                        Hello.          
Contents of section .comment:
 0000 00474343 3a202855 62756e74 7520352e  .GCC: (Ubuntu 5.
 0010 342e302d 36756275 6e747531 7e31362e  4.0-6ubuntu1~16.
 0020 30342e31 30292035 2e342e30 20323031  04.10) 5.4.0 201
 0030 36303630 3900                        60609.          
Contents of section .eh_frame:
 0000 14000000 00000000 017a5200 01781001  .........zR..x..
 0010 1b0c0708 90010000 1c000000 1c000000  ................
 0020 00000000 0f000000 00410e10 8602430d  .........A....C.
 0030 064a0c07 08000000                    .J......        

Disassembly of section .text:
0000000000000000 <my_function>:
   0:   55                      push   %ebp
   1:   48                      dec    %eax
   2:   89 e5                   mov    %esp,%ebp
   4:   48                      dec    %eax
   5:   c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%ebp)
   c:   90                      nop
   d:   5d                      pop    %ebp
   e:   c3                      ret    

Here's the C code:

void my_function () { 
   char* my_string = "Hello";
}

回答1:


You're disassembling 64-bit code as if it were 32-bit code. This is not normally possible unless you specifically override your disassembler or use objcopy or something to copy 64-bit machine-code into a 32-bit ELF object file.

x86-64 repurposed the 0x40..f bytes as REX prefixes instead of 1 byte encodings of inc/dec. The DEC EAX is actually a REX.W prefix, so the instruction is mov %rsp, %rbp for the normal frame-pointer setup.

This also explains the use of the top 8 bytes of the red-zone below the stack pointer. (x86-64 System V has a red-zone, i386 System V doesn't; it would move ESP before storing below it.) And it explains -8 instead of -4 for the pointer, because x86-64 has 8-byte pointers.


The 0 bytes are because you're disassembling a .o that isn't linked. Those 4 bytes of zeros will be filled in with the string's absolute address by the linker.

GCC is using a mov r/m64, sign_extended_imm32 here to store an 8-byte pointer to memory using a 32-bit absolute address as an immediate.

To put it in a register, we'd get the normal mov r32, imm32 (with implicit zero extension to 64-bit) for a non-PIE executable. But this code (with the default -O0 "debug mode") needs the whole 8-byte pointer in memory. It can still use a 32-bit absolute address instead of a RIP-relative LEA into a register + separate store, but it has to be explicit sign-extension to 64-bit.




回答2:


You are disassembling 64-bit code as if it were 32-bit code. The REX.W prefix, which exists in 64-bit code only, is the DEC EAX instruction in 32-bit code.



来源:https://stackoverflow.com/questions/56974052/understanding-disassembled-c-code-dec-eax-and-movl-0x0-0x8ebp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!