Условный вызов функции без использования других переходов? - PullRequest
0 голосов
/ 02 апреля 2019

Я хочу вызвать процедуру в зависимости от содержимого регистра.После завершения процедуры она должна вернуться к вызывающему адресу, чтобы программа могла продолжать выполнение кода, следующего за кодом операции call, в противном случае она должна игнорировать его и продолжать выполнение остальной части кода.

I 'я пытаюсь избежать просто условно перепрыгнуть через call с jcc, как в ответах на вызове подпрограмм условно в сборке описать.

Возможно ли это?Примерно так:

    cmp al,41h      ;check if register has value 41h
    call setAsize   ;call procedure if it does, otherwise ignore and continue executing code
   //more code to execute here


setASize:
    mov al,4d   ;change register content
    ret         ;return to call address so that code following call opcode can continue being executed

Как реализовать это без использования прыжка?

Ответы [ 2 ]

4 голосов
/ 02 апреля 2019

Я хочу вызвать процедуру в зависимости от содержимого регистра. ... Я пытаюсь избежать использования прыжка здесь. Является ли это возможным? ... Как реализовать это без прыжка?

К сожалению, большинство процессоров поддерживают условное выполнение только для команд перехода / перехода.

Процессоры ARM поддерживают условное выполнение почти всех инструкций; исторический 8080 и совместимые (8085, Z80) поддерживали условное выполнение CALL и RET в дополнение к прыжкам.

Однако процессоры x86 аналогичны большинству процессоров: только команды перехода могут быть выполнены условно.

Гипотетически, вы, возможно, могли бы использовать самоизменяющийся код в ОЗУ для условного выполнения любой инструкции без использования инструкций перехода. Тем не менее, выполнение этого было бы полезно только для некоторого технико-экономического обоснования, а не для любого реального случая использования.

3 голосов
/ 02 апреля 2019

Вы хотите реализовать структуру if-else в коде сборки, как показано в следующем C-коде

if (al == 0x41) { // we keep your example values
    // do something
    setASize();
} else {
    // do something else
    // not present in your code but there for the sake of completeness
}

В сборке вы напишите это следующим образом:

    cmp al, h41             ; this is the comparison, which sets flags 
    jne elseBranch          ; if the zero flag is *not* set (al != h41) jump to elseBranch
                        ; the jne instruction can be replaced with any other conditional
                        ; jump to adjust to the test condition
ifBranch:               ; useless label for clarity
    call setASize           ; this is the actual if-code (do-something)
    jmp endIf               ; now jump to the end of the if to avoid the else-branch
elseBranch:
                        ; nothing in your code, but this is where you put
                        ; your else instructions
endIf:
; now is the code after your if-else block, which will be executed in any case

Это один из двух классических способов написать блок if-else в сборке (обоснование такое же, только изменение инструкций). Другой вариант - поместить код else-ветки перед if-ветвью, чтобы получить более логичный условный переход (поскольку в первом примере мы проверяем равенство, но переходим, если не равен). С этим вторым вариантом код сборки будет

    cmp al, h41             ; this is the comparison, which sets flags 
    je ifBranch             ; if the zero flag is *not* set (al != h41) jump to elseBranch
                        ; the jne instruction can be replaced with any other conditional
                        ; jump to adjust to the test condition
elseBranch:             ; useless label for clarity
                        ; nothing in your code, but this is where you put
                        ; your else instructions
    jmp endIf               ; now jump to the end of the if to avoid the else-branch
ifBranch:
    call setASize           ; this is the actual if-code (do-something)
endIf:
; now is the code after your if-else block, which will be executed in any case

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


Для вашего кода, окончательный ответ будет:

    cmp al,41h
    jne endIf
    call setAsize
endIf:
                    ; more code here

setASize:
    mov al,4d
    ret
...