Язык ассемблера — соглашение о вызовах

Может ли кто-нибудь дать мне реальный пример, который поможет мне понять, что такое вызываемый объект и что такое вызывающий объект на ассемблере? Я просмотрел большинство источников, но до сих пор не могу понять, как отличить вызываемого от вызывающего. Заранее спасибо. (Я добавляю это объяснение - ЕЩЕ РАЗ СПАСИБО! извините за код, я здесь новичок и не знаю, как вставить код для правильного отображения) Я пытаюсь понять этот фрагмент кода - изучая основы сборки. Я пытаюсь добавить комментарий для каждой команды (я уверен, что кому-то еще, как мне, это тоже понадобится:

sub_401040      proc near               
.text:00401040
.text:00401040
.text:00401040 000                 push    ebp    ; Push the content of ebp register onto the stack
.text:00401041 004                 mov     ebp, esp    ;Allocating 8 bytes of storage ; move the esp register content into ebp register
.text:00401043 004                 push    ecx
.text:00401044 008                 mov     eax, [ebp+8]
.text:00401047 008                 push    eax    ; Push eax contents onto the stack
.text:00401048 00C                 call    ds:lstrlenA
.text:0040104E 008                 add     eax, [ebp+0Ch]
.text:00401051 008                 mov     edx, eax
.text:00401053 008                 mov     ecx, 1    ;Set buffer address
.text:00401058 008                 call    sub_401000
.text:0040105D 008                 mov     [ebp-4], eax
.text:00401060 008                 mov     ecx, [ebp-4]
.text:00401063 008                 shl     ecx, 2
.text:00401066 008                 mov     [ebp-4], ecx
.text:00401069 008                 mov     edx, [ebp-4]
.text:0040106C 008                 push    edx
.text:0040106D 00C                 push    offset aResultD ; "Result: %d\n"
.text:00401072 010                 call    ds:printf
.text:00401078 010                 add     esp, 8    ; clean up the stack by adding the size of the argument to esp register
.text:0040107B 008                 mov     eax, 539h
.text:00401080 008                 mov     esp, ebp
.text:00401082 004                 pop     ebp    ;Restore old frame pointer
.text:00401083 000                 retn        ; Return near
.text:00401083     sub_401040      endp

Я прочитал это, чтобы определить соглашение о вызовах, мне нужно выяснить, кто является вызывающим, а кто вызываемым :) Я потратил так много времени, чтобы понять логику: вызов ds:lstrlenA означает, что это вызываемый? а абонент sub_401040? и можем ли мы иметь более одного соглашения о вызовах в одной программе? как cdecl вместе с stdcall? Я не программист, и я не пишу код, я просто хочу понять, как это работает, чтобы помочь анализировать вирусы.


person Pierre C    schedule 19.02.2013    source источник
comment
Не уверен, что вы имеете в виду. Вы пишете код, верно? Итак, вы определяете соглашение о вызовах. Вы тот, кто читает из памяти, записывает в память, сохраняет регистры и т. д.   -  person Ed S.    schedule 19.02.2013


Ответы (3)


вызывающий — это тот, у кого есть соответствующая call (или инструкция вызова функции rcall/blx/jaalr/и т. д.), а вызываемый — это вызываемая функция.

func:
    do_stuff

func2:
    call func

В этом примере, когда func2 вызывает func, func2 называется вызывающим, а funcвызываемым.

Любая функция может быть либо вызывающей, либо вызываемой (или и той, и другой в разных контекстах), если только она не содержит call инструкций. В этом последнем случае это будет называться «функцией листа», и могут применяться некоторые оптимизации.

person nneonneo    schedule 19.02.2013

Когда некоторая функция/подпрограмма A вызывает другую функцию/подпрограмму B, A является вызывающей стороной, а B — вызываемой. Если B звонит C, то B становится вызывающим абонентом C, а C становится вызываемым B. Таким образом, B является одновременно вызывающим и вызываемым, в зависимости от того, как вы на это смотрите.

person Alexey Frunze    schedule 19.02.2013

В ассемблере вызов функции мало чем отличается от простого перехода (он же goto). Единственная разница в том, что параметры функции сохраняются в известном месте перед выполнением перехода, чтобы функция могла их прочитать и использовать. Одним из параметров обычно является адрес, по которому функция должна перейти после завершения своей работы, так называемый "обратный адрес". Прежде чем перейти по этому адресу, функция может сохранить возвращаемое значение в известном месте.

Таким образом, вызывающий объект — это фрагмент кода, который хранит параметры в известном месте, вызывает переход к началу функции, а затем, после того, как функция вернется к нему, считывает возвращаемое значение из известного места.

Вызываемый объект — это сама функция, т. е. фрагмент кода, к которому переходит вызывающий объект, который считывает параметры из известного места, выполняет некоторую работу на их основе, сохраняет возвращаемое значение в известном месте и переходит обратно к вызывающему объекту, используя предоставленный адрес возврата.

person Mikhail Vladimirov    schedule 19.02.2013