Как «таблицы дел» работают в NASM? - PullRequest
1 голос
/ 11 ноября 2011

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

Я действительно не могу понять смысл заметок, а книга - ноль справки (она вообще не упоминает)

    .data
CaseTable BYTE 'A'  ; lookup value
    DWORD Process_A ; address of procedure
    EntrySize = ($ - CaseTable)
    BYTE 'B'
    DWORD Process_B
    BYTE 'C'
    DWORD Process_C
    BYTE 'D'
    DWORD Process_D

NumberOfEntries = ($ - CaseTable) / EntrySize
….
segment .text
...
    mov ebx, CaseTable  ; point EBX to the table
    mov ecx,NumberOfEntries ; loop counter

L1: cmp al,[ebx]    ; match found?
    jne L2  ; no: continue
    call PTR [ebx + 1]  ; yes: call the procedure
    jmp L3  ; and exit the loop
L2: add ebx,EntrySize   ; point to next entry
    loop L1 ; repeat until ECX = 0

L3:

Может ли кто-нибудь помочь мне разобраться в этом?

1 Ответ

5 голосов
/ 11 ноября 2011

Идея тривиальна.Если вы не знаете достаточно ассемблера, попробуйте понять следующий эквивалентный код C (я взял на себя смелость определить Process _ * () как печать отдельных букв и добавив main ()):

#include <stdio.h>

void Process_A(void)
{
  printf("A\n");
}

void Process_B(void)
{
  printf("B\n");
}

void Process_C(void)
{
  printf("C\n");
}

void Process_D(void)
{
  printf("D\n");
}

typedef struct
{
  char Char;
  void (*Subroutine)(void);
} CaseTableEntry;

CaseTableEntry CaseTable[] =
{
  { 'A', &Process_A }, // equivalent to "BYTE 'A'" + "DWORD Process_A"
  { 'B', &Process_B },
  { 'C', &Process_C },
  { 'D', &Process_D }
};

void Process(char Char)
{
  const size_t NumberOfEntries = sizeof(CaseTable) / sizeof(CaseTableEntry);
  CaseTableEntry* entry = &CaseTable[0]; // equiv to "mov ebx, CaseTable"
  size_t count = NumberOfEntries; // equiv to "mov ecx, NumberOfEntries"

  do
  {
    // "L1:" would be here
    if (entry->Char == Char) // equiv to "cmp al,[ebx]" + "jne L2"
    {
      entry->Subroutine(); // equiv to "call PTR [ebx + 1]"
      break; // equiv to "jmp L3"
    }
    // "L2:" would be here
    entry++; // equiv to "add ebx, EntrySize"
  } while (--count > 0); // equiv to "loop L1"
  // "L3:" would be here
}

int main(void)
{
  Process('A');
  Process('B');
  Process('X');
  Process('C');
  Process('D');
  return 0;
}

Output:

A
B
C
D

Единственными проблемами здесь могут быть такие вещи, как $ и mov ebx, CaseTable.

$ оценивает положение сборки в начале строки, содержащей выражение;так что вы можете закодировать бесконечный цикл, используя JMP $.

Следовательно, EntrySize = ($ - CaseTable) вычисляет размер первой записи таблицы, а также NumberOfEntries = ($ - CaseTable) / EntrySize сначала вычисляет весь размер таблицы, а затем делит его наразмер одной записи дает вам количество записей таблицы.

В отличие от других ассемблеров (например, MASM и TASM), в NASM mov ebx, CaseTable означает загрузку в ebx адреса объекта с именем CaseTable.В других ассемблерах это может означать чтение в ebx первых 4 байтов от объекта с именем CaseTable.Точно так же DWORD Process_A определяет DWORD, содержащий адрес объекта с именем Process_A.
. В других ассемблерах эквиваленты, возможно, должны быть записаны как mov ebx, OFFSET CaseTable и DWORD OFFSET Process_A.

Для остальныхпожалуйста, обратитесь к своей книге, официальной документации NASM и Intel / AMD x86 CPU.Делай свою домашнюю работу, в основном.Если что-то не понятно, приходите и задавайте конкретных вопросов.

...