ВЫЗЫВАТЬ MASM, сохраняя регистры автоматически?

Можно ли автоматически сохранять регистры процессора, когда я использую директиву Invoke в masm?


person Jumbo    schedule 16.11.2010    source источник


Ответы (3)


Посмотрите на пример, который я разместил там: сортировка выбора на языке ассемблера

Директива USES в целевом PROC - это то, что вы ищете.
USES EAX ESI EDI автоматически сохранит эти регистры при входе в PROC и восстановит их при выходе (даже если у вас несколько точек RET и даже если имеется несколько точек ret не рекомендуется). IOW, он будет генерировать PUSH при вводе PROC и последовательно согласованные (в обратном порядке) POP перед каждым RET. Идея состоит в том, что, поскольку это сборка, у вас есть полный контроль и ответственность за те регистры, которые вы изменяете и хотите сохранить.
И вопреки тому, что было предложено где-то еще, объявление stdcall не сохраняет все автоматически для вас в MASM. Он просто определяет, отправляет ли вызывающий (код, сгенерированный для INVOKE) или вызываемый (код, сгенерированный в PROC) пармы.

person filofel    schedule 22.11.2010
comment
Этот вопрос касается invoke, а не proc. Или вы имеете в виду, что вы можете использовать uses с invoke? - person Abyx; 22.11.2010
comment
Единственное использование INVOKE - это вызов PROC с соглашением о вызовах, параметрами и т. Д. - person filofel; 23.11.2010
comment
INVOKE - это оболочка HLL для вызовов, соглашения об обработке вызовов, параметров и т. Д. Расширения INVOKE и PROC - это две стороны одной медали. Например, в соответствии с типом процедуры, параметры будут удалены вызывающей стороной (при возврате, генерируемой, таким образом, с помощью INVOKE) или вызываемой стороной (внутри процедуры непосредственно перед каждым RET). Нет и не может быть другого способа автоматического сохранения / восстановления регистров в MASM, кроме этого. В противном случае это делается вручную, для каждого вызова, путем PUSHing перед вызовом и POPping при возврате. - person filofel; 23.11.2010
comment
@filofel: INVOKE используется только для вызова PROC - правда? как насчет вызовов импортированных функций? Я могу написать invoke GetCommandLine, где proc? Что сохранит мои реестры? - person Abyx; 23.11.2010
comment
@abyx: Ну конечно. Насколько я понимаю, здесь мы говорим о чистой сборке. И PROC - это способ определения функции stdcall или cdecl с помощью masm. Если вы ВЫЗОВИТЕ GetCommandLine (), GetCommandLine сохранит ваши регистры. В то время как PROC сохранит только то, что вы явно указали, вы ИСПОЛЬЗУЕТЕ. Это проясняет? - person filofel; 25.11.2010
comment
@filofel: GetCommandLine не сохраняет ecx и edx. Как их сохранить автоматически? - person Abyx; 25.11.2010
comment
@abyx: встроенного способа сделать это автоматически в точке вызова нет. Единственные способы - это подтолкнуть регистры к вызову либо напрямую, либо через макрос, либо вызвать оболочку fnc, которая сделает это, а затем вызовет GetCommandLine (), но это ни в коем случае не является автоматическим. Дело в том, что общий способ сохранения регистров находится внутри вызываемого, а не от вызывающего, хотя бы для того, чтобы инструкции сохранения / восстановления существовали один раз в функции, а не в каждой точке вызова (что является причиной использования stdcall , это лучше, чем cdecl). - person filofel; 10.12.2010

Соглашение о вызове "stdcall" гарантирует, что функция не испортит регистры, кроме eax, edx, ecx. Если хотите сохранить edx и ecx - напишите макрос.

person Abyx    schedule 16.11.2010
comment
Есть ли способ заставить eax автоматически сохраняться, а затем автоматически восстанавливаться во время INVOKE? - person Jumbo; 18.11.2010
comment
@Jumbo вы можете написать макрос, чтобы сохранить его, но когда вы его восстановите, вы потеряете возвращаемое значение функции. - person Abyx; 18.11.2010
comment
На самом деле stdcall ничего не гарантирует в MASM. В лучшем случае можно было бы предположить, что функция должна вести себя именно так. Чтобы регистры автоматически сохранялись / восстанавливались, вы должны использовать директиву USES в определении PROC. Смотрите мой ответ. - person filofel; 22.11.2010

Не совсем уверен, что вы имели в виду, и поскольку ваш тег - masm32, я предполагаю, что Windows x86.

Что вполне возможно, так это передать все аргументы, которые требуются для вызова API, а затем просто вызвать нужную функцию. Я имею в виду, что когда вы запускаете в сборке для Windows, вам не нужно использовать регистры для «вызова» API, вам нужно протолкнуть аргументы, а затем вызвать (или вызвать) API.

Например, это:

push 0
push DWORD PTR SS:[EBP+8]
push 0
push 0
push 80000000h
push 80000000h
push 80000000h
push 80000000h
push 0CF0000h
push offset AppName
push offset ClassName
push 0h
call CreateWindowExA

в точности равно этому (на самом деле просто значения параметров разные):

invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
       WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
       CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
       hInst,NULL

Это то, что вы имели в виду, задавая свой вопрос?

person jyz    schedule 16.11.2010