Dlang - Understaning std.cycle () in the assembly

import std.range : cycle;
void foo() pure @safe {
    cycle([1, 2]);
}

Today I came across a program written in D. I am trying to understand its assembly code, starting with a simple function.

From asm output in D compiler :

pure nothrow @nogc @safe std.range.Cycle!(int[]).Cycle std.range.cycle!(int[]).cycle(int[]):
 push   rbp
 mov    rbp,rsp
 sub    rsp,0x40
 mov    QWORD PTR [rbp-0x20],rdi
 mov    QWORD PTR [rbp-0x10],rsi
 mov    QWORD PTR [rbp-0x8],rdx
 ... rest of the function

I tried to read this server time, but I can’t understand why it std.range.cycle()gets 3 arguments ( RDI, RSIand RDX) or where my range ( [1, 2]) is. Is this not a C-like structure?

Or am I missing something?

+4
source share
1 answer

, x86-64 SystemV ABI rdi rsi arg, Windows 64-bit ABI . . x86 wiki ABI docs .

(, structs), , . ( 128 ) , , RDX: RAX. , .

asm docs, , : , . D, . 64-, , RDX: RAX, .

, Cycle(),:

  • RDI: "" ( 64- )
  • RSI: arg ( range_start)
  • RDX: arg ( range_end)

, asm , , D , clang gcc, . -O -release -inline ( ), - / .

pure nothrow @nogc @safe std.range.Cycle!(int[]).Cycle std.range.cycle!(int[]).cycle(int[]):
 sub    rsp,0x28
 mov    QWORD PTR [rsp+0x20],rdi        # hidden first arg (return-value pointer).
 mov    QWORD PTR [rsp+0x8],0x0         # totally useless: overwritten without read

 mov    QWORD PTR [rsp+0x10],0x0        # totally useless: same.

 mov    QWORD PTR [rsp+0x8],rsi         # first "real" arg
 mov    QWORD PTR [rsp+0x10],rdx        # second "real" arg
 xor    eax,eax
 xor    edx,edx                         # zero rax:rdx.  Perhaps from the index=0 default when you only use one arg?
 div    QWORD PTR [rsp+0x8]             # divide 0 by first arg of the range.
 mov    QWORD PTR [rsp+0x18],rdx        # remainder of (index / range_start), I guess.
 lea    rsi,[rsp+0x8]                   # RSI=pointer to where range_start, range_end, and index/range_start were stored on the stack.
 movs   QWORD PTR es:[rdi],QWORD PTR ds:[rsi]  # copy to the dst buffer.  A smart compiler would have stored there in the first place, instead of to local scratch and then copying.
 movs   QWORD PTR es:[rdi],QWORD PTR ds:[rsi]  # movs is not very efficient, this is horrible code.
 movs   QWORD PTR es:[rdi],QWORD PTR ds:[rsi]
 mov    rax,QWORD PTR [rsp+0x20]        # mov rax, rdi  before those MOVS instructions would have been much more efficient.
 add    rsp,0x28
 ret    

ABI , RAX, . RAX.


:

std.range.Cycle...:
   mov    [rdi], rsi           # cycle_start
   mov    [rdi+0x8], rdx       # cycle_end
   mov    [rdi+0x10], 0        # index
   mov    rax, rdi
   ret

, . , , foo(), () .

, foo() , , , - .o( ) . , 00 00 00 00, . , , , esi = 2 edi = 0. ( mov edi, 0 ! Yuck!). , rel32 .

, LDC GDC , (LLVM gcc), -, , . , Matt Godbolt, D .

+7

Source: https://habr.com/ru/post/1654907/


All Articles