SIGSEGV При доступе к элементу массива с использованием сборки

Фон:

Я новичок в сборке. Когда я изучал программирование, я создал программу, которая реализует таблицы умножения до 1000 * 1000. Таблицы отформатированы так, чтобы каждый ответ был в строке factor1 << 10 | factor2 (Я знаю, я знаю, это не красиво). Эти таблицы затем загружаются в массив: int* tables, Пустые строки заполнены 0. Вот ссылка на файл для таблиц (7,3 МБ). Я знаю, что использование ассемблера не сильно ускорит это, но я просто хотел сделать это для развлечения (и немного практики).

Вопрос:

Я пытаюсь преобразовать этот код во встроенную сборку (tables является глобальным):

int answer;
// ...
answer = tables [factor1 << 10 | factor2];

Вот что я придумал:

asm volatile ( "shll $10, %1;""orl %1, %2;""movl _tables(,%2,4), %0;" : "=r" (answer) : "r" (factor1), "r" (factor2) );

Мой код C ++ работает нормально, но моя сборка не удалась. Что не так с моей сборкой (особенно movl _tables(,%2,4), %0; часть), по сравнению с моим C ++

Что я сделал, чтобы решить это:

Я использовал несколько случайных чисел: 89 796 как factor1 а также factor2, я знать что есть элемент в 89 << 10 | 786 (который 91922) — проверил это с помощью C ++. Когда я запускаю его с gdbЯ получаю SIGSEGV:

Программа получила сигнал SIGSEGV, Ошибка сегментации.

на этой линии:

"movl _tables(,%2,4), %0;" : "=r" (answer) : "r" (factor1), "r" (factor2) );

Я добавил два метода вокруг моего asmоткуда я знаю где asm Блок находится в разборке.

Разборка моего asm блок:

Разборка из objdump -M att -d выглядит хорошо (хотя я не уверен, я новичок в сборке, как я уже сказал):

402096: 8b 45 08                mov    0x8(%ebp),%eax
402099: 8b 55 0c                mov    0xc(%ebp),%edx
40209c: c1 e0 0a                shl    $0xa,%eax
40209f: 09 c2                   or     %eax,%edx
4020a1: 8b 04 95 18 e0 47 00    mov    0x47e018(,%edx,4),%eax
4020a8: 89 45 ec                mov    %eax,-0x14(%ebp)

Разборка из objdump -M intel -d:

402096: 8b 45 08                mov    eax,DWORD PTR [ebp+0x8]
402099: 8b 55 0c                mov    edx,DWORD PTR [ebp+0xc]
40209c: c1 e0 0a                shl    eax,0xa
40209f: 09 c2                   or     edx,eax
4020a1: 8b 04 95 18 e0 47 00    mov    eax,DWORD PTR [edx*4+0x47e018]
4020a8: 89 45 ec                mov    DWORD PTR [ebp-0x14],eax

Из того, что я понимаю, движется первый параметр моего void calc ( int factor1, int factor2 ) функция в eax, Затем он перемещает второй параметр в edx, Тогда это сдвиги eax влево на 10 и orс этим edx, 32-разрядное целое число составляет 4 байта, поэтому [edx*4+base_address]. Переместить результат в eax а затем положить eax в int answer (который, я думаю, включен -0x14 стека). Я не вижу особой проблемы.

Разборка компилятора .exe:

Когда я заменяю asm блок с простым C ++ (answer = tables [factor1 << 10 | factor2];) и разобрать это вот что я получаю в синтаксисе Intel:

402096: a1 18 e0 47 00          mov    eax,ds:0x47e018
40209b: 8b 55 08                mov    edx,DWORD PTR [ebp+0x8]
40209e: c1 e2 0a                shl    edx,0xa
4020a1: 0b 55 0c                or     edx,DWORD PTR [ebp+0xc]
4020a4: c1 e2 02                shl    edx,0x2
4020a7: 01 d0                   add    eax,edx
4020a9: 8b 00                   mov    eax,DWORD PTR [eax]
4020ab: 89 45 ec                mov    DWORD PTR [ebp-0x14],eax

В&Синтаксис T:

402096: a1 18 e0 47 00          mov    0x47e018,%eax
40209b: 8b 55 08                mov    0x8(%ebp),%edx
40209e: c1 e2 0a                shl    $0xa,%edx
4020a1: 0b 55 0c                or     0xc(%ebp),%edx
4020a4: c1 e2 02                shl    $0x2,%edx
4020a7: 01 d0                   add    %edx,%eax
4020a9: 8b 00                   mov    (%eax),%eax
4020ab: 89 45 ec                mov    %eax,-0x14(%ebp)

Я не очень знаком с синтаксисом Intel, поэтому я просто собираюсь попытаться понять AT&Синтаксис T:

Сначала перемещается базовый адрес tables массив в %eax, Затем это перемещает первый параметр в %edx, Это сдвиги %edx влево на 10, то orS со вторым параметром. Затем, сдвигая %edx слева на два, это на самом деле умножается %edx на 4. Затем это добавляет %eax (базовый адрес массива). Итак, в основном это просто сделано это: [edx*4+0x47e018] (Синтаксис Intel) или 0x47e018(,%edx,4) В&Т. Он перемещает значение элемента, в который он попал %eax и помещает это в int answer, Этот метод более «расширен», но он делает то же самое, что и моя рукописная сборка! Так почему мой дает SIGSEGV в то время как компилятор работает нормально?

0

Решение

Бьюсь об заклад (от разборки), что tables это указатель на массив, а не сам массив.

Итак, вам нужно:

 asm volatile ( "shll $10, %1;"movl  _tables,%%eax
"orl %1, %2;""movl (%%eax,%2,4)",
: "=r" (answer) : "r" (factor1), "r" (factor2) : "eax" )

(Не забывайте лишний клоббер в последней строке).

Конечно, есть варианты, это может быть более эффективным, если код находится в цикле:

 asm volatile ( "shll $10, %1;""orl %1, %2;""movl (%3,%2,4)",
: "=r" (answer) : "r" (factor1), "r" (factor2), "r"(tables) )
2

Другие решения

Это должно быть дополнением к ответу Матса Петерссона — я написал его просто потому, что мне не сразу было понятно, почему анализ разборки в OP (что его сборка и компиляция, сгенерированные компилятором были эквивалентны) был неверным.

Как объясняет Матс Петерссон, проблема в том, что tables на самом деле это указатель на массив, поэтому для доступа к элементу вам нужно дважды разыменовать. Теперь для меня это было не сразу понятно где это происходит в сгенерированном компилятором коде. Виновником является эта невинно выглядящая линия:

a1 18 e0 47 00          mov    0x47e018,%eax

Для неподготовленного глаза (включая моего) это может выглядеть как значение 0x47e018 перемещен в eax, но на самом деле это не так. Синтаксическое представление Intel тех же кодов операций дает нам подсказку:

a1 18 e0 47 00          mov    eax,ds:0x47e018

Ах — ds: — так что это на самом деле не значение, а адрес!

Для тех, кто интересуется сейчас, следующие будут коды операций и синтаксическая сборка ATT для перемещения значение 0x47e018 в eax:

b8 18 e0 47 00          mov    $0x47e018,%eax
2

По вопросам рекламы [email protected]