Kod po konwersji nie wykonuje danej czynności [duplikat]

Dec 18 2020

Dostałem zadanie konwersji określonego kodu z C ++ na ASM w oparciu o składnię AT&T, więc zacząłem od prostych przykładów i napotkałem pierwszy problem.

kod, od którego zacząłem ćwiczenie

void func() {
  int num = 1;
  std::cout << "before: " << num << std::endl;
  num = num << 3;
  std::cout << "after: " << num << std::endl;
}

co daje wynik:

before: 1
after: 8

moja zmienna translacyjna num jest pierwszą zmienną lokalną, więc powinna znajdować się w adresie -4 (% ebp)

void func() {
  int num = 1;
  std::cout << "before: " << num << std::endl;
  asm (
    "mov -4(%ebp), %eax         \n"
    "sall $3, %eax              \n"
    "mov %eax, -4(%ebp)         \n"
  );
  std::cout << "after: " << num << std::endl;
}

co daje wynik:

before: 1
after: 1

dlaczego ten kod nie ma wpływu na num var?

Odpowiedzi

2 JHBonarius Dec 18 2020 at 02:17

Kod, który piszesz, jest bardzo specyficzny dla implementacji. W twoim przypadku kod prawdopodobnie nie działa, ponieważ używasz ebp32-bitowego rejestru adresowego, podczas gdy pracujesz na komputerze 64-bitowym, który używa rbp.

JEDNAK podchodzisz do tego nieprawidłowo. Albo piszesz czysty asembler, albo używasz poprawnego (rozszerzonego) zestawu wbudowanego C, który poprawnie łączy się ze zmiennymi lokalnymi. W przeciwnym razie kod zepsuje się, gdy tylko coś zmienisz, czego doświadczyłeś.

zgodnie z tą odpowiedzią asm inline powinien wyglądać następująco:

asm ( "assembly code"
    : output operands                  /* optional */
    : input operands                   /* optional */
    : list of clobbered registers      /* optional */
);

więc twój kod może wyglądać

asm (
    "mov %0, %%eax;"
    "sal $3, %%eax;"
    "mov %%eax, %1;"
    :"=r" (num)
    :"r" (num)
    :"%eax"
);

Jednak nie musisz określać i używać eax, więc kod można uprościć (i wyjaśnić) do

asm (
    "sal $3, %[num];"
    :[num] "+r" (num)
);