Ответ 1
Проблема использования GCC inline asm для изучения сборки заключается в том, что вы тратите половину своего времени на изучение того, как работает сборка gcc inline, а не только на сборку. Например, здесь, как я могу написать этот же код:
#include <stdio.h>
int getStringLength(const char *pStr){
int len;
__asm__ (
"repne scasb\n\t"
"not %%ecx\n\t"
"dec %%ecx"
:"=c" (len), "+D"(pStr) /*Outputs*/
:"c"(-1), "a"(0) /*Inputs*/
/* tell the compiler we read the memory pointed to by pStr,
with a dummy input so we don't need a "memory" clobber */
, "m" (*(const struct {char a; char x[];} *) pStr)
);
return len;
}
Смотрите компилятор asm output в проводнике компилятора Godbolt. Вход в фиктивную память - это сложная часть: см. Обсуждение в комментариях и в списке рассылки gcc для наиболее оптимального способа сделать это, что все еще безопасно.
Сравнивая это с вашим примером
- Я не инициализирую
len
, так как asm объявляет его как выход (= c). - Нет необходимости копировать
pStr
, так как это локальная переменная. По спецификации нам уже разрешено изменять его (хотя, поскольку онconst
, мы не должны изменять данные, на которые он указывает). - Нет причин говорить встроенному asm о том, чтобы положить
Ptr
вeax
, только чтобы ваш asm переместил его вedi
. Я просто положил значение вedi
в первую очередь. Обратите внимание: поскольку значение вedi
изменяется, мы не можем просто объявить его как "вход" (по спецификации, inline asm не должен изменять значение входов). Изменение этого параметра на выход чтения/записи решает эту проблему. - Нет необходимости иметь asm zero
eax
, так как вы можете иметь ограничения для этого. В качестве побочного преимущества gcc "знает", что он имеет 0 в регистреeax
, и (в оптимизированных сборках) он может повторно использовать его (подумайте: проверяя длину 2 строки). - Я также могу использовать ограничения для инициализации
ecx
. Как уже упоминалось, изменение значения входов не допускается. Но поскольку я определяюecx
как результат, gcc уже знает, что я его меняю. - Поскольку содержимое ecx, eax и edi явно указано, нет необходимости больше ничего скрывать.
Все это делает для (слегка) более короткий и более эффективный код.
Но это смешно. Как, черт возьми, я могу сказать "heck" на SO?), Вы должны знать все это?
Если целью является изучение asm, использование inline asm не является вашим лучшим подходом (на самом деле я бы сказал, что inline asm является bad idea в большинстве случаев). Я бы рекомендовал вам объявить getStringLength как extern и полностью записать его в asm, а затем связать его с вашим кодом C.
Таким образом вы узнаете о передаче параметров, возвращаете значения, сохраняете регистры (наряду с изучением, какие регистры должны быть сохранены и которые можно безопасно использовать в качестве нуля), стек кадров, как связать asm с C и т.д. и т.д. и т.д. Все это более полезно знать, чем этот gobbledygook для встроенного asm.