2015-02-11 44 views
5

Niektóre architektury CPU (inne niż x86) nie lubią odczytu i zapisu liczb wielobajtowych na niezaalokowanych adresach tak bardzo, że po wykryciu tego powodu wywołują wyjątek SIGBUS i zmuszają programistę do zrobienia wszystkiego ręcznie w porządku bajtowym . Chociaż nie można nic zrobić z platformami, które tego wymagają, głupotą byłoby sprawdzanie wyrównania i przeprowadzanie operacji bajtowych na platformach, które umożliwiają niewyrównany dostęp (jak na przykład x86). Pytanie brzmi: czy kompilatory C/C++ definiują stałą, która wskazuje wymaganie wyrównania?Wymóg wyrównania pamięci stałej kompilatora

Obecnie używam to:

#if defined(_M_IX86) | defined(__i386) | defined(__i386__) | defined(i386) | defined(_X86_) 
    // Unaligned access is allowed. 
#elif defined(_M_X64) | defined(__x86_64__) | defined(__x86_64) | defined(__amd64) | defined(__amd64__) | defined(_M_AMD64) 
    // Unaligned access is allowed. 
#else 
    #define ALIGNED_ACCESS_ONLY 
#endif 

Ale wygląda zbyt „home-napar”: zamiast wskazywać rzeczywiste właściwości bieżącej platformy sprzętowej, a jedynie przedstawia swoje własne rozważania o x86-32 oraz x86-64 i najbardziej popularne nazwy stałe dla tych platform.

+0

Oczywistym rozwiązaniem byłoby połowu 'SIGBUS' po starając się niewyrównany dostęp ... – edmz

+0

@black To będzie ciężki * * Przypuszczam, że: nawet jeśli połowu wyjątek Hardware szybko (co zdecydowanie wątpię), w każdym razie zainstalowanie programu obsługi, wychwycenie błędu i usunięcie programu obsługi nigdy nie może być tak szybkie, jak proste sprawdzenie wyrównania adresu, a następnie odpowiednie rozgałęzienie. Niewyrównany dostęp w moim przypadku to podstawowy tryb działania, a nie rzadka sytuacja. –

+0

Rzeczywiście; Właśnie zaproponowałem temu "rozwiązanie ubogich ludzi". Czy możesz nam powiedzieć, czy chcesz to wiedzieć, czy próbujesz rozwiązać konkretny problem [XY] (https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)? – edmz

Odpowiedz

1

Nie odpowiadam technicznie na zadane pytanie, ale proponuję obejście problemu w przypadku, gdy odpowiedź na twoje pytanie brzmi "nie".

Jeśli twój kod został skompilowany za pomocą skryptu configure, możesz przetestować, czy wymagany jest dostęp wyrównany. GNU autoconf posiada funkcję dla tej operacji:

http://www.gnu.org/software/autoconf-archive/ax_check_aligned_access_required.html

Zasadniczo kompiluje następujące mały program, prowadzi go i patrzy na skutek:

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    char* string = malloc(40); 
    int i; 
    for (i=0; i < 40; i++) 
    { 
    string[[i]] = i; 
    } 

    { 
    void* s = string; 
    int* p = s+1; 
    int* q = s+2; 

    if (*p == *q) { return 1; } 
    } 
    return 0; 
} 
+0

byłoby piękne, gdybyś "uwolnił" pamięć, ale plus jeden. – Bathsheba

+0

Dla jasności, kod pochodził z autoconfa GNU, a ja dodałem tylko spacje i nawiasy, aby wyjaśnić, co zawiera pętla for. Możesz przypisać im łatkę. –

+0

DavidGrayson: Czy jest jakiś szczególny powód, dla którego nie są one tylko przydzielaniem stosów 'string'? I @ Batszaba: Wiem, że niektórzy ludzie będą mnie nienawidzić za to, że to mówili, ale GNU nigdy nie było znane z jakości kodu. –

0

Rozwiązanie, które nie wymaga sprawdź, czy to taki, który widziałem w implementacji memcpy. Zasadniczo zaczniesz kopiować bajt danych na bajt, aż dojdziesz do adresu wielokrotnego żądanego wyrównania.
Po tym można rozpocząć kopiowanie fragmentów danych o rozmiarze słowa ze wszystkimi korzyściami, jakie masz z wyrównanym adresem (rozwijanie pętli, wektoryzacja, ...).

Zyskasz jednak najlepsze wyniki dzięki dużym blokom danych.

Najwyraźniej ani clang ani gcc nie określają żadnego makra informującego o braku dostępu. (gcc/clang -E -dM - < /dev/null -march=native).
Kilka pomysłów, które warto wziąć pod uwagę:

  • zmniejszyć zapotrzebowanie na pierwszym miejscu: problemy ponieść podczas korzystania wskazówek. Staraj się tego unikać, zmieniając sposób, w jaki traktujesz swoje dane.
  • asm: Zapisz zależnie od platformy asm, aby załadować/zapisać do/z niezaakceptowanego dostępu, chociaż w dużym stopniu zależy to od platform, z którymi współpracujesz.
  • SSE umożliwia dostęp bez uprawnień.
+0

Czytam/piszę pojedynczą liczbę na raz, nawet jeśli niektóre liczby są czasami pogrupowane w tablice (a nawet w tym przypadku są one w większości przypadków niezaliczone). –

+0

@AntonSamsonov Dodano kilka innych opcji. Jednak wciąż trudno jest wyodrębnić możliwe rozwiązania bez * rzeczywistego * kodu. – edmz

-2

Kompilatory OP: do C/C++ definiują stałą, która wskazuje na konieczność wyrównania?
Tak. max_align_t to typ określający maksymalne wyrównanie.

Jeśli jest to sizeof(max_align_t) > 1, konieczne jest wyrównanie.

Dla zanim C11, zobacz Compiler constant indicating memory alignment requirement

+0

To nie odpowiada na jego pytanie. Pytał, czy dozwolony dostęp jest dozwolony, a nie to, jakie jest maksymalne wyrównanie. Na przykład x86 zazwyczaj ma maksymalne wyrównanie '8' lub' 16', ale mimo to umożliwia dostęp z wyrównaniem '1' (są po prostu wolniejsze); z drugiej strony, MIPS i ARM podnoszą błędy dla niewyrównanych wejść. –

+0

@ Tim Čas OP pyta "czy kompilatory C/C++ definiują stałą, która wskazuje wymaganie wyrównania?", Pogrubieniem. Proste sprawdzenie, czy 'sizeof (max_align_t) == 1' wskazywałoby, czy konieczne jest wyrównanie. – chux

+1

Wskazuje, czy obiekty powinny być wyrównane, ale istnieje * nie * wskazanie, czy obsługiwane są nieprzydzielone dostępy. W x86 musisz * wyrównać, ale * nie musisz *. W ARM lub MIPS * musisz * wyrównywać (lub cierpieć z powodu błędów "SIGBUS"). OP pytał, czy istnieje sposób sprawdzenia, czy * trzeba * wyrównać, a nie czy * należy *. –