WedX - журнал о программировании и компьютерных науках

Сборка x86: вызов malloc не помещает указатель на выделенную память в регистр EAX

Я пытаюсь выделить 40 байт пространства в памяти, вызвав внешнюю команду C malloc в сборке x86 (синтаксис AT&T/Intel). Однако, когда я отлаживаю свою программу, регистр EAX не изменился после вызова команды malloc (насколько я понимаю, процедура использования malloc заключается в том, чтобы поместить количество байтов, которые вы хотите выделить, в регистр EDI, а затем выполнить вызов malloc поставить указатель на блок памяти, размещенный в регистре EAX). Ниже мой код сборки x86:

.extern malloc

.text
.global main
main:
    movl %esp, %ebp #for correct debugging
    # write your code here
    xorl  %eax, %eax
    
    movl $40, %edi
    call malloc
    
    ret

Я использую 32-битное соглашение (не 64-битное) в Linux.

Команда компиляции:

gcc -m32 -Wall -g -c -o program.o program.s
23.11.2020

  • Да, но 32-битное соглашение не использует edi для передачи аргумента, это 64-битное. 32-битный аргумент передается в стек. Вы хотите push $40; call malloc; mov %ebp; %esp; ret 23.11.2020
  • Вы ориентируетесь на x86-64 или x86 (32-разрядная версия). Соглашение о вызовах с EDI предполагает 64-разрядную версию, но вы выполняете операции, связанные со стеком, с ESP вместо RSP. Вы используете Windows или MacOs/Linux/BSD? Как вы наблюдаете значение в EAX? В отладчике или глядя на возвращаемое значение программы (возвращаемое значение программы 8 бит) 23.11.2020
  • Хорошо, тогда @Jester прав, вам нужно поместить параметры в стек с помощью i386 System V ABI (они помещаются справа налево). Кроме того, современный Linux ABI требует, чтобы стек был правильно выровнен по крайней мере по 16-байтовой границе для вызовов функций, совместимых с ABI (включая библиотеку C). Неправильное выравнивание стека может работать в некоторых средах, но может вызывать ошибки в других средах в зависимости от того, как построены функции (например, библиотека C). 23.11.2020
  • С другой стороны, EBP — это регистр, сохраняемый вызываемым пользователем (энергонезависимый), поэтому, если вы измените его в main, вы должны сохранить его значение (поместить EBP в стек в начале), а затем восстановить его (извлечь EBP) до того, как вы ret из main 23.11.2020
  • @MichaelPetch Верно. 23.11.2020

Ответы:


1
call malloc

где мой толчок?

push %edi
call malloc
add  %esp, 4 ; caller cleans up the stack

Итак, они говорят мне, что современный glibc теперь навязывает выравнивание стека байтов. Я не в состоянии подтвердить это, но ты просто обязан это сделать. Выглядело бы сейчас так:

sub  %esp, 8
push %edi
call malloc
add  %esp, 12 ; caller cleans up the stack
23.11.2020
  • Однако для этого все еще требуется выравнивание стека. 23.11.2020
  • @NateEldredge: В прошлый раз, когда я делал это на 32-битной версии, мне было все равно. И если это важно сейчас, то мои программы glibc, скомпилированные в 1999 году, больше не работают. Glibc пообещал фиксированный ABI. Он изменился? 23.11.2020
  • Текущая версия i386 System V ABI, которую использует Linux, делает на бумаге требует/гарантирует 16-байтовое выравнивание стека. Но если ваш glibc не скомпилирован с включенным SSE2, то сам glibc вряд ли когда-либо будет зависеть от этого. А если и удавалось, то только для копирования 4-х вещей размером с int/pointer, а не просто пары, как в 64-битном режиме. Основная потенциальная проблема заключается в обратном вызове вашего собственного кода, если вы скомпилировали его с помощью -march=native, или в другую библиотеку, скомпилированную с включенным SSE2. (отправьте сообщение @NateEldredge, если вам интересно) 23.11.2020
  • Re: старые бинарники: -mpreferred-stack-boundary=4 уже давно используется по умолчанию. Раньше это было просто хорошей идеей, но мало кто заметил, что 32-битный SSE2 генератор кода GCC создавал код, который зависел от него, пока двоичные файлы, построенные таким образом, не получили широкого распространения, и в этот момент меньше всего -Плохой путь вперед состоял в том, чтобы сделать это законом. См. ссылки в верхней части Почему x86-64/AMD64 System V ABI предписывает выравнивание стека по 16 байт? для грязной истории для 32-разрядных: gcc.gnu.org/bugzilla/show_bug.cgi ?id=40838#c91 – увеличенная версия этой сводки. 23.11.2020
  • @PeterCordes: Ну вот и все. Мои 32-битные процессоры не имеют SSE, и компилятор такой же старый. Поэтому, если я вызову 32-битный компилятор, я получу 4-байтовое выравнивание стека. Современная машина увидит выравнивание стека по 8 байт. На моем современном компьютере есть только *32 для запуска программ, которые буквально нельзя скомпилировать в 64-битную версию, и библиотеки *32 для поддержки этих программ. Таким образом, glibc должен быть скомпилирован для его поддержки, иначе двоичные файлы просто рухнут. 23.11.2020
  • Хотя этот вопрос касается Linux, MacOS использует тот же 32-битный ABI (для версий MacOS, которые все еще поддерживают эту архитектуру), и malloc, скорее всего, выйдет из строя из-за ошибки (большая часть библиотеки C там будет). Я только что попробовал и подтвердил, что без надлежащего выравнивания он не работает с выровненными инструкциями SSE. Я бы не стал полагаться на код, который не выполняет надлежащее выравнивание. Я думаю, что одно место в Linux, которое может вызвать ошибку, — это printf GLIBC с двойным параметром. 23.11.2020
  • @Joshua: Итак, если я вызову 32-битный компилятор, я получу 4-байтовое выравнивание стека. - это не совсем так. GCC, вероятно, по умолчанию использовал -mpreferred-stack-boundary=4 или по крайней мере 3 до появления SSE, чтобы разрешить 8-байтовое выравнивание для double локальных переменных на P5 Pentium. В любом случае, тот факт, что ваша 32-разрядная установка де-факто обратно совместима со старыми двоичными файлами, которые могут привести к смещению стека, не означает, что вы можете безопасно говорить всем в Интернете делать то же самое в 32-разрядной версии. битовый код. Эта ошибка/оплошность разработчиков GCC, которая привела к несовместимости ABI, отстой для всех :( 23.11.2020
  • Что касается вашего редактирования, стек смещается на 4, когда инструкция вызова передает управление функции main, потому что адрес возврата был передан. Чтобы выровнять его обратно по 16-байтовой границе, вам придется уменьшить ESP на 12 к моменту вызова malloc. (или 12, 28, 44 и т. д.) 23.11.2020
  • @MichaelPetch: Да, я думал, что что-то не так. Современный способ состоит в том, чтобы перестроить всю функцию, чтобы использовать инструкции mov, но я не собираюсь делать это посреди чьей-то ручной сборки. 23.11.2020
  • Также обратите внимание, что OP хочет выделить константу 40 байт; они используют EDI только для передачи аргументов. Поэтому вы должны использовать push $40, а не push %edi. Кроме того, да, это правильное выравнивание стека, если вы оставляете их сломанные mov %esp, %ebp без push/pop EBP вокруг него. Поэтому, если вы собираетесь попытаться исправить всю их функцию, чтобы она была совместима с ABI, затирание EBP является такой же большой или большей проблемой, как выравнивание 16-байтового стека (особенно в 32-битном коде). 23.11.2020
  • @PeterCordes: я игнорирую сохранение реестра, потому что это main. Любая другая функция, и это я бы тоже исправил. 23.11.2020
  • Вызывающая функция main (из кода CRT), как правило, снисходительна, но в C другим функциям разрешено вызывать main, и в этом случае ваша программа, скорее всего, сломается, если main уничтожит регистры, которых не должно быть. Или лучший аргумент заключается в том, что будущие читатели могут захотеть использовать этот код в других функциях, поэтому, по крайней мере, комментарии о нарушениях ABI, которые вы разрешаете, имеют смысл. например # push %ebp # skipped in main because its caller usually doesn't care 23.11.2020
  • Или, возможно, есть дубликат, который мы могли бы использовать, чтобы закрыть этот вопрос, вместо того, чтобы прилагать усилия для ответа. 23.11.2020
  • @PeterCordes Недавно я добавил команду компиляции, которую использую. 23.11.2020
  • С кодом в вашем ответе указатель на выделенную память помещен в регистр EAX? 23.11.2020
  • Для справки современный i386 System V ABI в разделе The Кадр стека говорит следующее: конец области входных аргументов должен быть выровнен по границе 16 (32, если __m256 передается в стек) байтов. . Другими словами, значение (%esp + 4) всегда кратно 16 (32), когда управление передается точке входа в функцию 23.11.2020
  • Новые материалы

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    Для любых предложений по сайту: [email protected]