Не получается изменить переменную из ассемблерной вставки

85
11 октября 2021, 13:40

https://wandbox.org/permlink/fNyh3Nj0LroooFFq

#include <cstring>
#include <iostream>
using namespace std;
char *doSmth(char *s)
{
  volatile register char *p asm("rax") = s;
  __asm__
  ("\
    .intel_syntax noprefix   \n\
    inc rax                  \n\
    inc byte ptr [rax]       \n\
  ");
  return (char*)p;
}
int main()
{
  char s[] = "abcXYZ";
  cout << s << ' ' << doSmth(s) << endl;
  return 0;
}

Выводится

abcXYZ accXYZ

т. е. инкремент символа происходит верно, а инкремент указателя тоже как бы происходит (изменён верный символ), но только внутри ассемблерной вставки и не отражается на переменной, используемой в дальнейшем коде.

А хотелось бы получить строку с ожидаемо отрезанным первым символом:

abcXYZ ccXYZ

Как исправить?

Answer 1

Компилятор же не знает, что вы там внутри переменную p поменяли, и берёт значение не из регистра, а из переменной s (её-то вы не меняли, а там записано то же самое). Это один из вариантов, на самом деле их до чёрта. Такая ситуация называется UB (undefined behavior).

Чтобы компилятор не занимался самодеятельностью, надо рассказать ему какие переменные изменялись. Например, так:

char *doSmth(char *s)
{
  __asm__ volatile (
    "inc %0\n"
    "incb (%0)\n"
  : "+r"(s) : : "memory");
  return s;
}

Здесь "+r" (s) означает, что переменная s должна быть доступна для чтения и записи как регистр, а volatile и "memory" означают, что в процессе могли измениться посторонние данные (т.е. не являющиеся ни входными параметрами, ни выходными).

Подробнее о синтаксисе можно прочитать здесь: https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html

Answer 2

У меня результат зависит от включённой оптимизации.

Работает, как предполагалось, при

--- testold.cpp 2019-10-30 12:25:49.539828727 +0100
+++ test.cpp    2019-10-30 12:24:11.419439287 +0100
@@ -9,7 +9,6 @@
 __asm__
 ("\
-    .intel_syntax noprefix   \n\
     inc rax                  \n\
 ");

и компиляции с g++ -masm=intel test.cpp. Если не указывать -masm=intel, то не ассемблируется. Если собирать с -O1 или выше, то переменная не изменяется.

user@host:~/path$ ./a.out
1234567 234567
user@host:~/path$

Debian, amd64, g++ 6.3.0

READ ALSO
Где ошибка в обьекте?

Где ошибка в обьекте?

Нужно создать обьект вот такой структуры:

316
Как правильно обернуть эти JS-скрипты?

Как правильно обернуть эти JS-скрипты?

Плохо разбираюсь в семантике JS, помогите,пожалуйстаБраузер ругается на лишние символы в данных скриптах

67