0

I want to understand the initialization in x86 assembly of the following float array. I compiled it with "gcc -O0".

#include <stdio.h>

int main(void) {
    float d[] = {1, 2, 3, 4};
    printf("d=[%f, %f, %f, %f]\n", *(d+0), *(d+1), *(d+2), *(d+3));
    return 0;
}

1 in floating point representation is 0x3f800000, 2 is 0x40000000, 3 is 0x40400000, and 4 is 0x40800000. I can't find any of this numbers (0x3f8, 0x400, 0x404, 0x408) in the assembler output. But why?

I got the following disassembly:

0000000000001169 <main>:
    1169:   f3 0f 1e fa             endbr64 
    116d:   55                      push   %rbp
    116e:   48 89 e5                mov    %rsp,%rbp
    1171:   48 83 ec 20             sub    $0x20,%rsp
    1175:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
    117c:   00 00 
    117e:   48 89 45 f8             mov    %rax,-0x8(%rbp)
    1182:   31 c0                   xor    %eax,%eax
    1184:   f3 0f 10 05 8c 0e 00    movss  0xe8c(%rip),%xmm0        # 2018 <_IO_stdin_used+0x18>
    118b:   00 
    118c:   f3 0f 11 45 e0          movss  %xmm0,-0x20(%rbp)
    1191:   f3 0f 10 05 83 0e 00    movss  0xe83(%rip),%xmm0        # 201c <_IO_stdin_used+0x1c>
    1198:   00 
    1199:   f3 0f 11 45 e4          movss  %xmm0,-0x1c(%rbp)
    119e:   f3 0f 10 05 7a 0e 00    movss  0xe7a(%rip),%xmm0        # 2020 <_IO_stdin_used+0x20>
    11a5:   00 
    11a6:   f3 0f 11 45 e8          movss  %xmm0,-0x18(%rbp)
    11ab:   f3 0f 10 05 71 0e 00    movss  0xe71(%rip),%xmm0        # 2024 <_IO_stdin_used+0x24>
    11b2:   00 
    11b3:   f3 0f 11 45 ec          movss  %xmm0,-0x14(%rbp)
    11b8:   f3 0f 10 45 ec          movss  -0x14(%rbp),%xmm0
    11bd:   f3 0f 5a d8             cvtss2sd %xmm0,%xmm3
    11c1:   f3 0f 10 45 e8          movss  -0x18(%rbp),%xmm0
    11c6:   f3 0f 5a d0             cvtss2sd %xmm0,%xmm2
    11ca:   f3 0f 10 45 e4          movss  -0x1c(%rbp),%xmm0
    11cf:   f3 0f 5a c8             cvtss2sd %xmm0,%xmm1
    11d3:   f3 0f 10 45 e0          movss  -0x20(%rbp),%xmm0
    11d8:   f3 0f 5a c0             cvtss2sd %xmm0,%xmm0
    11dc:   48 8d 3d 21 0e 00 00    lea    0xe21(%rip),%rdi        # 2004 <_IO_stdin_used+0x4>
    11e3:   b8 04 00 00 00          mov    $0x4,%eax
    11e8:   e8 83 fe ff ff          callq  1070 <printf@plt>
    11ed:   b8 00 00 00 00          mov    $0x0,%eax
    11f2:   48 8b 55 f8             mov    -0x8(%rbp),%rdx
    11f6:   64 48 33 14 25 28 00    xor    %fs:0x28,%rdx
    11fd:   00 00 
    11ff:   74 05                   je     1206 <main+0x9d>
    1201:   e8 5a fe ff ff          callq  1060 <__stack_chk_fail@plt>
    1206:   c9                      leaveq 
    1207:   c3                      retq   
    1208:   0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
    120f:   00 

As far as I understand initialization is done here.. but I don't understand whats happening. Why 0xe8c?

    1184:   f3 0f 10 05 8c 0e 00    movss  0xe8c(%rip),%xmm0        # 2018 <_IO_stdin_used+0x18>
    118b:   00 
    118c:   f3 0f 11 45 e0          movss  %xmm0,-0x20(%rbp)
    1191:   f3 0f 10 05 83 0e 00    movss  0xe83(%rip),%xmm0        # 201c <_IO_stdin_used+0x1c>
    1198:   00 
    1199:   f3 0f 11 45 e4          movss  %xmm0,-0x1c(%rbp)
    119e:   f3 0f 10 05 7a 0e 00    movss  0xe7a(%rip),%xmm0        # 2020 <_IO_stdin_used+0x20>
    11a5:   00 
    11a6:   f3 0f 11 45 e8          movss  %xmm0,-0x18(%rbp)
    11ab:   f3 0f 10 05 71 0e 00    movss  0xe71(%rip),%xmm0        # 2024 <_IO_stdin_used+0x24>
    11b2:   00 
    11b3:   f3 0f 11 45 ec          movss  %xmm0,-0x14(%rbp)
    11b8:   f3 0f 10 45 ec          movss  -0x14(%rbp),%xmm0

What's happening here?

phip1611
  • 5,460
  • 4
  • 30
  • 57
  • 2
    You're only looking at the `.text` section, not `.rodata` where those `movss 0xe7a(%rip),%xmm0` loads are loading from. x86 doesn't have FP immediates. It's easier to look at the compiler's asm output directly, not assemble + disassemble, because then the only data will be your data. [How to remove "noise" from GCC/clang assembly output?](https://stackoverflow.com/q/38552116) – Peter Cordes May 22 '20 at 20:19
  • How did you know that `0xe7a` points to .rodata section? Is there a convention? I found the data there, so thanks. Why is .rodata not used when it's an int array? In this case I can find the data in `.text` EDIT: Thanks! – phip1611 May 22 '20 at 20:23
  • 1
    Because I know that's where GCC will put FP literal constants to copy from. If you want to learn that for yourself, look at GCC's asm output which includes `.section .rodata`. An `int` array can be initialized on the stack with mov-immediate stores. (In fact so could FP, using mov-immediate to store 32-bit FP bit patterns, but you disabled optimization so GCC definitely won't look for that.) – Peter Cordes May 22 '20 at 20:27
  • 1
    For example, https://godbolt.org/z/eum9Bj shows GCC `-O3` using a 64-bit integer immediate to hold the bit patterns for float `1.0` and `2.0`, so it can init `volatile float foo[] = {1.0, 2.0};` on the stack. – Peter Cordes May 22 '20 at 20:38

0 Answers0