Неправильно выровненные указатели на x86

Использование с 2 подзапросами вместе с UNION ALL и NOT IN должно работать для вас. Первый запрос выберет 40 строк, упорядоченных по ranking, второй запрос с подзапросом выберет все остальные строки , кроме первые 40 строк, которые уже выбраны первым подзапросом, и упорядочит его по score. Предложение UNION ALL объединит эти 2 записи подзапроса в один набор. Надеюсь, что это помогает и понятно :) сейчас.

 SELECT * FROM tbl_featured_professional ORDER BY ranking LIMIT 40
 UNION ALL
 SELECT * FROM tbl_featured_professional WHERE id NOT IN (SELECT * FROM tbl_featured_professional ORDER BY ranking LIMIT 40) 
 ORDER BY score
19
задан 9 revs 23 May 2017 в 12:34
поделиться

5 ответов

Существует дополнительное, не упомянутое условие, чтобы EFLAGS.AC действительно вступил в силу. CR0.AM должен быть установлен, чтобы предотвратить отключение INT 17h в старых операционных системах, предшествующих 486, которые не имеют обработчика для этого исключения. К сожалению, Windows не устанавливает его по умолчанию, вам нужно написать драйвер режима ядра, чтобы установить его.

3
ответ дан 30 November 2019 в 03:20
поделиться

символ *нечто, вероятно, выровненный к международным границам. Попробуйте это:

int bar = *(int *)(foo + 1);
3
ответ дан 30 November 2019 в 03:20
поделиться

Ситуации являются редкими, где невыровненный доступ вызовет проблемы на x86 (вне наличия доступа к памяти, занимают больше времени). Вот некоторые из тех, я услышал о:

  1. Вы не могли бы считать это как x86 проблема, но операционное преимущество SSE от выравнивания. Выровненные данные могут использоваться в качестве исходного операнда памяти для сохранения инструкций. Инструкции невыравнивать-загрузки как movups медленнее, чем movaps на микроархитектуре перед Nehalem, но на Nehalem и позже (и семейство Бульдозера AMD), невыровненные 16-байтовые загрузки/хранилища почти так же эффективны как невыровненные 8-байтовые загрузки/хранилища; единственный uop и никакой штраф вообще, если данные, оказывается, выровненные во времени выполнения или не пересекают границу строки кэша, в других отношениях эффективную поддержку оборудования для разделений строки кэша. Разделения 4k являются очень дорогими (~100 циклов) до Skylake (вниз к ~10 циклам как разделение строки кэша). См. https://agner.org/optimize / и ссылки производительности в wiki тега x86 для большего количества информации

  2. , взаимно блокируемые операции (как lock add [mem], eax) очень медленные, если они не достаточно выровненные, особенно если они пересекают границу строки кэша, таким образом, они не могут только использовать блокировку кэша в ядре процессора. В более старых (ошибочных) системах SMP они могли бы на самом деле сбой, чтобы быть атомарными (см. https://blogs.msdn.com/oldnewthing/archive/2004/08/30/222631.aspx).

  3. и другая возможность, обсужденная Raymond Chen, при контакте с устройствами, которые имеют окруженную валом память аппаратных средств (по общему признанию чудная ситуация) - https://blogs.msdn.com/oldnewthing/archive/2004/08/27/221486.aspx

  4. , который я вспоминаю (но не имейте ссылки для - таким образом, я не уверен в этом), подобные проблемы с невыровненными доступами, которые колеблются между границами страницы, которые также включают отсутствие страницы. Я буду видеть, могу ли я вскопать ссылку для этого.

И я изучил что-то новое при изучении этого вопроса (я задавался вопросом о" $ps |= (1<<18)" команда GDB, которая была упомянута в паре мест). Я не понял, что x86 центральные процессоры (запускающийся с 486, которыми это кажется) имеют способность вызвать исключение, когда неправильно выровненный доступ выполняется.

От "Программирования Jeffery Richter Приложений для Windows, 4-й Ed":

Позволяют нам более тщательно изучить то, как x86 ЦП обрабатывает выравнивание данных. x86 ЦП содержит специальный битовый флаг в своем регистре EFLAGS, названном AC (проверка выравнивания) флаг. По умолчанию этот флаг обнуляется, когда ЦП сначала получает питание. Когда этот флаг является нулем, ЦП автоматически делает то, что он имеет к тому, для успешного доступа к неправильно выровненным значениям данных. Однако, если этот флаг установлен на 1, ЦП выпускает INT 17-е прерывание каждый раз, когда существует попытка получить доступ к неправильно выровненным данным. x86 версия Windows 2000 и Windows 98 никогда не изменяет этот флаговый бит ЦП. Поэтому Вы никогда не будете видеть, что исключение неточного совмещения данных происходит в приложении, когда оно будет работать на x86 процессоре.

Это было новостями мне.

, Конечно, большая проблема с неправильно выровненными доступами состоит в том, что, когда Вы в конечном счете идете для компиляции кода для non-x86/x64 процессор, Вы заканчиваете тем, что имели необходимость разыскать и зафиксировать целый набор материала, так как фактически все другие 32-разрядные или более крупные процессоры чувствительны к проблемам выравнивания.

21
ответ дан 30 November 2019 в 03:20
поделиться
char *foo = "....";
foo++;
int *bar = (int *)foo;

компилятор поместил бы нечто на границу слова, и затем при постепенном увеличении его, это в word+1, который недопустим для международного указателя.

2
ответ дан 30 November 2019 в 03:20
поделиться
#include <stdio.h>

int main(int argc, char **argv)
{
  char c[] = "a";

  printf("%d\n", *(int*)(c));
}

Это дает мне SIGBUS после установки set $ps |= (1<<18) в gdb, который, по-видимому, брошен, когда выравнивание адреса неправильное (среди других причин).

Править: Довольно легко повысить SIGBUS:

int main(int argc, char **argv)
{
    /* EDIT: enable AC check */
    asm("pushf; "
        "orl $(1<<18), (%esp); "
        "popf;");

    char c[] = "1234567";
    char d[] = "12345678";
    return 0;
}

Рассмотрение дизассемблирования основного в gdb:

Dump of assembler code for function main:
....
0x08048406 <main+34>:   mov    0x8048510,%eax
0x0804840b <main+39>:   mov    0x8048514,%edx
0x08048411 <main+45>:   mov    %eax,-0x10(%ebp)
0x08048414 <main+48>:   mov    %edx,-0xc(%ebp)
0x08048417 <main+51>:   movl   $0x34333231,-0x19(%ebp)   <== BAM! SIGBUS
0x0804841e <main+58>:   movl   $0x38373635,-0x15(%ebp)
0x08048425 <main+65>:   movb   $0x0,-0x11(%ebp)

Во всяком случае, Christoph, которого Ваша тестовая программа приводит к сбою в соответствии с Linux, повышающим SIGBUS, как это должно. Это - вероятно, вещь Windows?


Можно включить Контрольный бит Выравнивания в коде с помощью этого отрывка:

/* enable AC check */
asm("pushf; "
    "orl $(1<<18), (%esp); "
    "popf;");

Кроме того, удостоверьтесь, что флаг был действительно установлен:

unsigned int flags;
asm("pushf; "
    "movl (%%esp), %0; "
    "popf; " : "=r"(flags));
fprintf(stderr, "%d\n", flags & (1<<18));
2
ответ дан 30 November 2019 в 03:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: