Помогите понять инструкцию DIV во встроенной сборке x86

Читая исходный код в проекте GNU, я наткнулся на этот фрагмент встроенной сборки:

__asm__ (
  "divq %4"
  : "=a" (q), "=d" (r)
  : "0" (n0), "1" (n1), "rm" (d)
);

Здесь переменные q, r, n0, n1 и d являются 64-битными целыми числами. Я достаточно знаю ассемблер, чтобы понять, что это делает, но есть некоторые детали, в которых я не уверен.

Что я понимаю:

Мы делим содержимое регистра RAX на d, помещаем частное в q, а остаток помещаем в r.

Чего я не понимаю

  1. Почему здесь три входа? Нам нужно ввести только делимое и делитель, так какой смысл может быть в 3-х входных данных?
  2. Я не могу сказать, какой из входов является дивидендом. В общем, я не вижу, чтобы в регистр RAX загружалось что-либо, так как же он узнает, что на что делить?

person Channel72    schedule 27.12.2010    source источник
comment
+1 хорошо отформатированный вопрос. Мне нравятся разделы «что я понимаю» и «что я не понимаю».   -  person R.. GitHub STOP HELPING ICE    schedule 29.12.2010


Ответы (2)


В спецификации входных операндов:

: "0" (n0), "1" (n1), "rm" (d)

регистры «0» и «1» принудительно заменяются rax и rdx из-за выходной спецификации:

: "=a" (q), "=d" (r)

А семейству инструкций div нужен числитель в RDX:RAX. Делитель может находиться в регистре общего назначения (не используемом иным образом, т. е. не в RAX или RDX) или в памяти, что определяется ограничением "rm". Регистры RDX, RAX и операнд делителя составляют 3 входа.

Таким образом, это приведет к выполнению деления: n1:n0 / d, где n1:n0 — количество, загруженное в rdx:rax.

person Michael Burr    schedule 27.12.2010
comment
правильно ли я понимаю, что это можно использовать для деления 128-битного целого числа на 64-битное целое? Я знал, что это возможно для 32-битной версии регистра, но никогда не думал, что это будет работать и для 64-битной версии. - person Jens Gustedt; 28.12.2010
comment
@Jens: это правильно. Но помните, что (как и операции деления меньшего операнда), если частное окажется слишком большим для регистра назначения rax, вы получите исключение деления. - person Michael Burr; 28.12.2010
comment
Быстрый способ проверить этот случай — просто убедиться, что rdx меньше делителя, и в этом случае деление безопасно. - person R.. GitHub STOP HELPING ICE; 29.12.2010

Как вы правильно заметили, семейство div работает с фиксированными регистрами a и d, rax и rdx для divq. Регистр a получает входные данные от n0, который является псевдонимом 0-го регистра, а именно a. n1 — это фиктивный ввод с псевдонимом d, вероятно, просто для того, чтобы этот регистр не использовался для других целей.

person Jens Gustedt    schedule 27.12.2010