- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
#include <iostream>
using namespace std;
void enable_misalignment_access_check(){
cout<<"begin "<<__FUNCTION__<<endl;
__asm__(
"pushf\n"
"orl $(1<<18),(%esp)\n"
"popf\n"
);
cout<<"end "<<__FUNCTION__<<endl;
}
void alignedAccess(volatile unsigned char foo[])
{
cout<<"begin "<<__FUNCTION__<<endl;
volatile int t = *(int *)(foo);
cout<<"end "<<__FUNCTION__<<endl;
}
void unalignedAccess(volatile unsigned char foo[])
{
cout<<"begin "<<__FUNCTION__<<endl;
volatile int t = *(int *)(foo+1);
cout<<"end "<<__FUNCTION__<<endl;
}
unsigned char foo[] = { 1, 2, 3, 4, 5, 6 };
int main(void)
{
alignedAccess(foo);
unalignedAccess(foo);
enable_misalignment_access_check();
alignedAccess(foo);
unalignedAccess(foo);
return 0;
}
Пока в голову приходят только #pragma pack(1) и извраты с кастами char* в указатели на что-то более крупное.
То, что ты сейчас увидишь - в этом тоже велосипеды виноваты (не дождались из-за великов):
https://pp.vk.me/c540101/v540101687/9b20/l8cH679aVPY.jpg
Ты так говоришь, как-будто это что-то плохое.
> Я думал кресты по стандарту в конец структур не дописывают мусор.
Я тоже так думал, и боялся за массивы. Но как оказалось - массивы тоже будут ровными и шелковистыми. А в стандарте этот момент я не читал...
Кстати, а у вижуалки как с этим?
скимпилировалось без нареканий
Этот момент описывается не в крестах. Это имплементэйшн дефайнед - другими словами "ABI".
Мои велосипеды не имеют аналогов в STL. Вернее, один имеет, но только в STL сипипоха, а не в моём.
Hardcode успокоился, TarasB прилёг рядом с ним, и так вместе они читали стандарт языка. Последним остался Kartonagnick. У него вдруг подогнулись ноги, и он рассердился на себя.
— Неслыханно, — пробурчал Kartonagnick. — TarasB знает кресты, а Kartonagnick боится!
С этими словами он перелистнул страницу стандарта. Но ему показалось, что голова у него стала чугунная, и охватила его такая тьма, что даже он, Kartonagnick, без страха измеривший глубочайшие подвалы языка, вдруг попросил всё это развидеть.
Это намек на то, что Тарас знает кресты или намек на то, что Хардкод - кавказец? А насколько у него жесткий?
Что-за цитата? Я со школы ничего не читал.
1. Сам удалил пост — можно попытаться уложиться в лимит времени на редактирование.
2. Сам отругал админов — пишешь красным от имени админа причину удаления, потом пишешь ответ.
3. Сам себя забанил — сменил пароль.
Ну вроде всё возможно.
(Простите за мой любимый вид комментария.)
Сейчас попробую крешдамп собрать и посмотреть на него.
через std::align выровнять можно буфер заведомо большего размера
А нету :(
Да там питушня полнейшая. Можно даже ничего не выводить, тупо включить AC и выйти. После чего сразу же пидорасит кишки libc с тем самым bus error...
Короче не хочу я с этим связываться, пускай гейдевовцы сами разбираются со своей проверкой.
P.S. А вот на ARM'овских линухах таких проблем быть не должно, там то поди все выравнивания вылизаны.
Может тогда компилятор староват? Они небось пока в стандарт не ввели С++11, то о выравнивании не сильно заботились. Может ключики нужно указать на выравнивание? А вообще гейдевовцы обычно VirtualAlloc вызывают, что бы на границу параграфа (16 или сколько там нужно для ссе) было выравнено. В линуксе должно быть похожее. Кстати, за это тоже хочется убить.
Там походу какое-то горе от ума, ибо тот же __memcpy_sse2 падает не на sse'шной команде, а на вполне безобидном в обычном режиме муве: mov (%rsi), %ecx
Либо программист отвечает за alignment'ы входного и выходного буфера, либо придется копировать по одному символу (можно, конечно, в ряде случаев копировать по 4 или по 8 вместо 16, но производительность будет уже не та...), либо насрать на выравнивания, и делать так, как это сделано сейчас ;(
Это худший случай.
Если же разность адресов не кратна - придется копировать меньшими блоками, т.к. ты никогда не выровняешь оба буфера под нормальное 16-байтное копирование. Либо один удачно встанет, либо второй, но не оба сразу.
А сейчас на x86 и x86_64 сделано довольно тупо - копируется байт, потом два и т.д. до 8, пока размер копируемого блока не выровняется на 16, а дальше идет блочное копирование (насрав на alignment).
В одном случае из 16, если об этом не позаботились заранее ;)
Требоваться то оно не требуется, но с выравниванием всяко будет быстрее, меньше кешлайнов затронет и т.п...
Да здесь в memcpy и его друзьях дело. Походу 128 битные загрузки/сохранения даже в невыровненном виде быстрее чем побайтовое копирование. Поэтому libc'шники на x86 и x86_64 и пожертвовали alignment'ом.
P.S. У фряхи же вроде своя сишная либа, не libc?
Я заведу тип {char; T} и разберу случаи равнения на 1,2,4. На остальные пока выдам ошибку компиляции. Мне хватит этого на первое время, но ненадолго. Надеюсь, что вскоре за мной придёт помощь.
Как было показано выше по треду - первый же memcpy развалит всю эту надежность к хуям. Т.к. невозможно сделать одновременно быстрый и alignment-safe memcpy. Если memcpy работает с AC - значит он копирует все по одному байту, или тебе просто повезло, и оба буфера были хорошо выровнены (что при копировании строк не с начала и их конкатенации - просто случайность).
Так что сойдет разве что для небольших тестов своего кода, которые не затрагивают стандартную либу и не юзают memcpy по невыровненным адресам (читай - не используют строки).
А если тупо потестить свой контейнер на наличие проблем с выравниванием - почему бы и нет.