Какова цель ADD BX, 2 в этом коде? - PullRequest
1 голос
/ 26 марта 2019

Я пытаюсь понять этот код рекурсии, но я запутался в том, что является целью add bx, 2.Я поставил отметку в соответствующей строке.Как я понимаю, мы должны увеличивать указатель, указывающий на массив, значениями, но почему мы добавляем 2, а не 1?

    .model small
    .stack 100
    .data
     arr dw 38, 39, 90, 94, 13, 24, 53, 59, 63
     size dw 9
     result dw ?
    .code
    func proc
     push bp
     mov bp, sp
     push ax
     push bx
     push cx
     push dx
     mov cx, [bp+4]
     mov bx, [bp+6]
     mov ax, [bx]
     cmp cx, 1
     ja more
     mov [bp+6], ax
     jmp done
    more:

     **add bx, 2**

     push bx
     dec cx
     push cx
     call func
     pop dx
     cmp dx, ax
     jg greater
     mov [bp+6], ax
     jmp done
    greater:
     mov [bp+6], dx
    done:
     pop dx
     pop cx
     pop bx
     pop ax
     pop bp
     ret 2
    func endp

Ответы [ 2 ]

5 голосов
/ 26 марта 2019

Как я понимаю, мы должны увеличивать указатель, указывающий на массив, со значениями, но почему мы добавляем 2, а не 1?

Если я правильно понимаю, BX очковпо адресу элемента в массиве, содержащем 16-битные значения.

Инструкция mov ax, [bx] показывает, что элементы являются 16-битными значениями, а не 8- или 32-битными значениями.16-битное значение имеет длину 2 байта.

На большинстве процессоров (есть исключения, такие как TMS 320 или TMS 9900), разница между адресами двух элементов в массиве составляет n, если элементимеет длину n байт.

Таким образом, если x является адресом элемента в массиве, содержащем 16-битные значения, а y является адресом следующего элемента, то y-x=2.

Следовательно, два должны быть добавлены к BX, чтобы получить адрес следующего элемента.

2 голосов
/ 26 марта 2019

Обратите внимание на push bx / ... / call func впоследствии: это рекурсивная функция, и она передает bx+2 следующему вызову.

Я думаю, что BX используется как указатель, и есть arr, который является массивом "слов" (2 байта), так что это почти наверняка приращение указателя.

Это выглядит очень неэффективно; он только однократно рекурсивный, поэтому его очень легко записать в виде цикла. например, do { something with *p++; } while(--cx); в C, то есть цикл с dec cx / jnz внизу.

Кроме того, ветвление довольно глупо: оно может проверять состояние завершения рекурсии намного раньше, перед тем, как сохранить столько регистров. И это может вывести jmp из нормального пути через функцию, используя jna done. Возможно, в конце функции потребуется перейти к специальному блоку, поместив 2 перехода на путь особого случая, но это все же лучше, чем 2 перехода на основной путь.

Также странно хранить / перезагружать вещи в [bp+6]. Эта функция возвращает, изменяя один из своих аргументов в стеке? Это выглядит так на основе pop dx сразу после звонка. Я надеюсь, что это намеренно запутано или написано в качестве отправной точки для оптимизации, потому что это выглядит чрезмерно сложным.

Основываясь на именах целей ветвления, я предполагаю, что это просто нахождение максимального слова со знаком в массиве, учитывая указатель и длину. Это тривиально и намного эффективнее с циклом.

...