2016-06-29 14 views
7

Niedawno natrafiłem na pojęcia rejestru połączeń i funkcji listków.Dlaczego ARM mówi, że "Rejestr linków obsługuje wywołania funkcji szybkiego liścia"

Rozumiem z poprzedniego SO, że LR mówi, gdzie kod był poprzednio podczas wykonywania. Dowiedziałem się także, że funkcja liścia jest funkcją, która pojawia się na końcu hierarchii wywołań funkcji.

ARM wikipedia page says: rejestr

Link obsługuje szybkich wywołań funkcji liść.

Dlaczego to roszczenie jest prawdziwe? Spojrzałem na ARMARM (Podręcznik Architektury), a informacje w rejestrze linków są minimalne.

+3

Należy zauważyć, że współczesne mikroarchitektury zwykle mają sprzętowe stosy powrotne, które przewidują, do którego funkcja powróci, umożliwiając spekulacyjne wykonanie przez zwrot. Nawet procesory bez rejestru linków nie czekają na ponowne załadowanie adresu zwrotnego z pamięci. – EOF

Odpowiedz

2

Na niektórych architekturach (takich jak x86, x86_64), adres powrotu z funkcji jest zawsze przechowywane na stosie i wywołanie funkcji implikuje dostęp do pamięci głównej:

  • write do stosu, gdy powołanie;

  • a odczyt ze stosu przy powrocie.

Natomiast jeśli architektura/ABI może skakać/powrót bez korzystania z pamięci głównej i parametry i powrócić wartości odbierającym mogą być przekazywane w rejestrach, jak również, połączenie i powrócić do/z funkcji liściowych można to zrobić bez angażowania pamięci RAM.

Jeśli funkcja liść jest na tyle prosty, może to wykonać bez dotykania RAM w ogóle:

int callee(int a, int b) 
{ 
    return a + b; 
} 

int caller(int a, int b, int c, int d) 
{ 
    return callee(a,b) + calle(c,d); 
} 

daje (każdą funkcję skompilowany oddzielnie clang -target arm-eabi -S -o- -O3):

callee: 
    add r0, r1, r0 
    bx lr 
caller: 
    .save {r4, r5, r6, r10, r11, lr} 
    push {r4, r5, r6, r10, r11, lr} 
    .setfp r11, sp, #16 
    add r11, sp, #16 
    mov r4, r3 
    mov r5, r2 
    bl callee 
    mov r6, r0 
    mov r0, r5 
    mov r1, r4 
    bl callee 
    add r0, r0, r6 
    pop {r4, r5, r6, r10, r11, lr} 
    bx lr 

Wskazówki w jaki sposób możemy uniknąć dostęp do pamięci w rdzeniu caller i calee.

+0

Dlaczego mówisz o typie zwrotu funkcji? Rejestr łącza przechowuje adres zwrotny, a nie wartość zwracaną ani typ zwracany. – blatinox

+0

@blatinox, miałem na myśli "adres" :) – ysdx

+0

Możesz użyć '__attribute __ ((noinline)), aby uzyskać dane wyjściowe kompilatora z jednej jednostki kompilacji, [jak to na Godbolt] (https://godbolt.org/g/YoJJGj) –

2

Powód jest taki, że podczas wywoływania funkcji liścia adres zwrotny nie musi być wypychany na stos (ponieważ jest przechowywany w rejestrze linków). To powinno być szybsze niż przesuwanie adresu zwrotnego do stosu, tak jak to robisz w procesorach, które nie mają rejestru linków (ale nie ma pewności, że są one rzeczywiście szybsze).

Istnieją jednak sytuacje, w których funkcja listka musi mimo wszystko zapisywać dane w stosie. Na przykład funkcja listkowa z wieloma zmiennymi może wymagać użycia stosu do przechowywania lub zapisywania rejestru linków w celu zwolnienia tymczasowych rejestrów.

+0

W którym ABI rejestr linków może być używany jako rejestr tymczasowy? – blatinox

+2

@blatinox Normalny ABI. Normalnym sposobem zwracania funkcji innej niż liść jest wywołanie adresu zwrotnego ze stosu (bez przywracania rejestru linków), w związku z czym osoba wywołująca nie może założyć, że rejestr linków zachowuje wartość, którą umieścił w rejestrze. Zwykle rejestr linków jest używany w ten sposób. – skyking

Powiązane problemy