Смешивание c ++ и ассемблера не может передать несколько параметров из функции C ++ в ассемблер - PullRequest
0 голосов
/ 24 мая 2018

Я был разочарован передачей параметров из функции c ++ в сборку.Я не смог найти что-нибудь, что помогло бы в Google и действительно нуждалось бы в вашей помощи.Я использую Visual Studio 2017 и masm для компиляции моего кода сборки.

Это упрощенная версия моего файла c ++, где я вызываю процедуру сборки set_clock

int main()
{
    TimeInfo localTime;
    char clock[4] = { 0,0,0,0 };
    set_clock(clock,&localTime); 
    system("pause");
    return 0;
}

Я сталкиваюсь с проблемами в файле сборки.Я не могу понять, почему второй параметр, переданный функции, оказывается огромным.Я сходил со своего учебника, в котором показан аналогичный код с PROC, за которым следуют параметры.Я не знаю, почему первый параметр прошел успешно, а второй - нет.Может кто-нибудь сказать мне правильный способ передачи нескольких параметров?

.code
set_clock PROC, 
    array:qword,address:qword
    mov rdx,array   ; works fine memory address: 0x1052440000616
    mov rdi,address ; value of rdi is 14757395258967641292
    mov al, [rdx] 
    mov [rdi],al    ; ERROR: cant access that memory location
    ret
set_clock ENDP
END

1 Ответ

0 голосов
/ 24 мая 2018

Дерьмо высокого уровня от MASM кусает тебя в задницу. x64 Windows передает первые 4 аргумента в rcx, rdx, r8, r9 (для любого из тех 4, которые являются целыми числами / указателями).

mov rdx,array
mov rdi,address

собирается в

mov  rdx, rcx    ; clobber 2nd arg with a copy of the 1st
mov  rdi, rdx    ; copy array again

Используйте дизассемблер, чтобы проверить себя.Всегда хорошая идея проверять реальный машинный код, разбирая или используя разборку отладчиков вместо режима исходного кода, если с макросами на ассемблере происходит что-то странное.


Я не уверен, почему этоприведет к недоступной ячейке памяти .Если оба аргумента действительно являются указателями на локальные объекты, тогда он должен просто загружаться и сохраняться в том же месте стека.Но если char clock[4] - это const в статическом хранилище, это может быть страница памяти только для чтения, которая объясняет сбой хранилища.

В любом случае, используйте отладчик и узнайте.


Кстати, rdi - это сохраняемый вызов (он же энергонезависимый) регистр в соглашении x64 Windows.(https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx). Используйте регистры с ограниченным вызовом для чистых регистров, если вы не исчерпали себя и вам не нужно сохранять / восстанавливать некоторые сохраненные вызовы регистры. См. Также Соглашение о вызовах Agner Fog doc (http://agner.org/optimize/), и другие ссылки в тег x86 wiki .

Он перекрыт вызовом в x86-64 System V, которая также передает аргументы в разные регистры. Может быть, вы смотрели другой пример?


Надеюсь исправленная версия, использующая movzx, чтобы избежать ложной зависимости от RAX при загрузке байта.

set_clock PROC, 
    array:qword,address:qword
    movzx    eax, byte ptr [array] 
    mov      [address], al
    ret
set_clock ENDP

Я не использую MASM, но я думаю, что array:qword делает arrayпсевдоним для rcx. Или вы можете пропустить объявление параметров и просто использовать rcx и rdx напрямую, и задокументировать это с комментариями. Это будет легче для всех понять.

Вы определенно не понимаетевам не нужны бесполезные mov reg,reg инструкции, загромождающие ваш код; если вы пишете в asm, то напрасные инструкции могут привести к ускорению, которое вы получаете.

...