Долгое время пользователь MSVC, новичок в gcc (так что терпите меня).
Я использую версию c ++ rubenvb (см. Версию в теме, да, я строю для 64-битной) на Windows 7, и у меня возникли проблемы с использованием _BitScanForward64. Пример кода выглядит так:
int __cdecl main(int argc, char* argv[])
{
DWORD d = (DWORD)atoi(argv[1]);
DWORD ix, ix2;
ix2 = _BitScanForward64(&ix, d);
printf("bsf %u %u\n", ix, ix2);
}
Я собираю с:
«C: \ Program Files \ gcc2 \ mingw64 \ bin \ c ++. Exe» -o iTot.exe -mno-ms-bitfields -march = native -momit-leaf-frame-pointer -mwin32 -Os -fomit-frame-pointer -m64 -msse4 -mpopcnt -D WINDOWS main.cpp
Когда я запустил iTot.exe, используя параметр 8, я ожидал, что _BitScanForward64 установит для ix значение 3. Это то, что делает MSVC. Однако ix равен 0, а ix2 равен 1.
Также, глядя на ассемблера, я вижу:
bsfq QWORD PTR 44[rsp],rax # MEM[(volatile LONG64 *)&ix], Mask
При таких обстоятельствах, почему gcc заставляет память писать + читать здесь?
Итак, несколько вопросов:
Взглянув на вывод ассемблера из -S, я не увидел ничего плохого в генерируемом коде. Однако, используя objdump.exe -d -Mintel, Я вижу, что вместо того, чтобы использовать приведенный выше код asm (который, похоже, будет работать), он на самом деле произвел обратное:
bsf rax, QWORD PTR [rsp + 0x2c]
WTF? Почему-лжет мне?
Как я уже сказал, я новичок в gcc, поэтому, если я просто делаю что-то глупое, будь осторожен со мной. Благодарю.
Хорошо, я думаю, что ответил на свои вопросы. Спасибо Joachim PileBorg, который заставил меня посмотреть, где было определение, и Алексею Фрунзе, который указал, что params не может быть отсталым
Хотя я слишком новичок в gcc, чтобы говорить об этом авторитетно, я считаю, что определение _BitScanForward64 в winnt.h очень неверно.
Текущее определение:
__CRT_INLINE BOOLEAN _BitScanForward64(DWORD *Index,DWORD64 Mask) {
__asm__ __volatile__("bsfq %1,%0" : "=r" (Mask),"=m" ((*(volatile LONG64 *)Index)));
return Mask!=0;
}
Мое определение:
__CRT_INLINE BOOLEAN BSF(DWORD *Index,DWORD64 Mask) {
LONG64 t;
__asm__ ("bsfq %0,%1" : "=r" (Mask),"=r" (t));
*Index = t;
return Mask!=0;
}
Обратите внимание на удаление (ненужной) volatile, обращение параметров к bsfq, изменение с = m на = r и т. Д. По сути, кажется, что это определение настолько неверно, насколько это возможно, и все еще компилируется.
Я предполагаю, что человек, который написал это, посмотрел на прототип для BitScanForward64 и «знал», что один из параметров должен быть памятью, и так как единственный, который Можно быть памятью для BSF это p2, вот что они сделали. Как написано, код будет читать неписанное содержимое p2 и сканировать его на биты. Компилируется, но выдает неправильный ответ.
Итак, чтобы принять мои вопросы по порядку:
-S неправильно записывает выходной файл (у objdump все правильно). Использование моего определения выше дает:
call atoi
lea rcx, .LC0[rip]
/APP
# 7 "m.cpp" 1
bsfq rax,rdx
/NO_APP
call printf
И это не то, что на самом деле находится в исполняемом файле. Фактический исполняемый файл содержит (правильное) определение:
bsfq rdx,rax
Хотя я не в восторге от изменения файлов заголовков системы, похоже, что это будет мой ответ здесь. Если кто-то знает, как и где сообщить об этой проблеме, чтобы она была исправлена (как я уже говорил, я использую reubenvb), я мог бы сообщить об этих двух проблемах, так что (надеюсь) это будет исправлено для всех.
Других решений пока нет …