От: Идеологическая диверсия!

Автор kol1978, 21 декабря 2024, 16:34:55

« назад - далее »

0 Пользователи и 3 гостей просматривают эту тему.

kol1978

"Идеологическая диверсия — термин, который официально использовался в СССР на государственном уровне..."
И так! На сайте https://asm.sourceforge.net/articles/linasm.html содержится следующая информация:
ЦитироватьВведение.
В этой статье будет описано программирование на языке ассемблера в Linux. В рамках статьи приводится сравнение синтаксиса ассемблера Intel и AT&T, руководство по использованию системных вызовов и вводное руководство по использованию встроенного ассемблера в gcc.
Пример:
 __asm__("test %%eax,%%eax", : /* без вывода */ : "a" (foo));
или
 __asm__("test %%eax,%%eax", : /* без вывода */ : "eax" (foo));

Вместо того чтобы писать "eax" и принудительно использовать конкретный регистр, такой как "eax", "ax" или "al", вы можете просто указать "a".
Базовая встроенная сборка в gcc очень проста. В своей базовой форме она выглядит следующим образом:

 __asm__("movl %esp,%eax"); // знакомо ?
(Цитата из раздела «Инструкции ассемблера с операндами в виде выражений C» в информационных файлах gcc.)
Возможно, вы заметили, что к регистрам теперь добавляется префикс «%%», а не «%». Это необходимо при использовании полей вывода/ввода/изменения, поскольку можно использовать псевдонимы регистров на основе дополнительных полей.
Так же приводиться текст программы:
Цитировать-----------nano inline1.c
#include <stdio.h>
int main(void) {
 int foo=10,bar=15;
 
 __asm____volatile__ ("addl %%ebxx,%%eax"
 : "=eax"(foo) // вывод
 : "eax"(foo), "ebx"(bar)// ввод
 : "eax" // изменение
 );
 printf("foo+bar=%d\n", foo);
 return 0;
}


21 декабря 2024, 21:43:48
Результатом компиляции
Цитироватьgcc inline1.c -o inline1
является ошибка :
Цитироватьinline1.c: In function 'main':
inline1.c:8:2: warning: implicit declaration of function '__asm____volatile__' [-Wimplicit-function-declaration]
    8 |  __asm____volatile__ ("addl %%ebxx,%%eax"
      |  ^~~~~~~~~~~~~~~~~~~
inline1.c:8:42: error: expected ')' before ':' token
    8 |  __asm____volatile__ ("addl %%ebxx,%%eax"
      |                      ~                   ^
      |                                          )
    9 |  : "=eax"(foo) // вывод
      |  ~
Все верно? но не понятно..., но если убрать подчеркивания и оставить только asm вместо __asm____volatile__, появиться более вразумительная ошибка :
Цитироватьkol@kol-VirtualBox:~/develop_kernel_modules/syscall/TEST$ gcc inline1.c -o inline1
inline1.c: Сообщения ассемблера:
inline1.c:8: Ошибка: плохое имя регистра: «%ebxx»
Вот теперь точно верно - что лишний x или по нашему Ха 8)
Исправляем :
Цитировать#include <stdio.h>
/*register int foo=10;
register int bar=15;
 */
int main(void) {
 int foo=10,bar=15;
 
 __asm____volatile__ ("addl %%ebx,%%eax"
 : "=eax"(foo) // вывод
 : "eax"(foo), "ebx"(bar)// ввод
 : "eax" // изменение
 );
 printf("foo+bar=%d\n", foo);
 return 0;
}
Результат компиляции:
Цитироватьkol@kol-VirtualBox:~/develop_kernel_modules/syscall/TEST$ ./inline1
foo+bar=791621423
Арифметика впечатляет? хотя у Вас может быть другое число... :P
А если так :
Цитировать#include <stdio.h>
/*register int foo=10;
register int bar=15;
 */
int main(void) {
 int foo=10,bar=15;

 asm("addl %%ebx, %%eax"
 : "=a"(foo) // вывод
 : "a"(foo), "b"(bar)// ввод
// : "a" // изменение
 );
 printf("foo+bar=%d\n", foo);
 return 0;
}
то  :
Цитироватьkol@kol-VirtualBox:~/develop_kernel_modules/syscall/TEST$ ./inline1
foo+bar=25
уже можно кричать ура и победа!? Это вопрос - если убрать лишнее // перед третьим : (двоеточием) :-\
 

Лия

#1
Цитата: kol1978 от 21 декабря 2024, 16:34:55__asm____volatile__
с пробелом
__asm__ __volatile__

21 декабря 2024, 18:53:12
#include <stdio.h>

int main(void) {
 int foo=10, bar=15;

 __asm__ __volatile__("addl %%ebx, %%eax"
 : "=a"(foo)
 : "a"(foo), "b"(bar)
 );
 printf("foo+bar=%d\n", foo);
 return 0;
}

21 декабря 2024, 18:54:00
https://av-assembler.ru/asm/high-level-languages/assembler-gcc.php

dzhoser

Синтаксис ассемблера:

Ваша строка __asm____volatile__ содержит лишние символы. Правильный синтаксис — __asm__ __volatile__.
Использование регистров:

В строке "addl %%ebxx, %%eax" вы ошиблись в названии регистра. Правильный регистр — %%ebx, а не %%ebxx.
Выходные и входные операнды:

В выходных операндах вы указали "=eax"(foo), что является ошибкой. Правильный синтаксис —  "=a"(foo), где a указывает на регистр eax.
Входные операнды также должны быть исправлены на "a"(foo), "b"(bar).

Изменение регистров:

В списке изменений вы указали "eax", но это не требуется. Вы можете просто опустить эту часть, так как вы уже указали, какие регистры используются в выходных и входных операндах.
Ubuntu->Linux mint->Astra Linux SE->Debian 12
Для новичков

kol1978

#3
теперь уверен что ты робот.

25 декабря 2024, 10:36:31
Цитата: Лия от 21 декабря 2024, 18:45:07
Цитата: kol1978 от 21 декабря 2024, 16:34:55__asm____volatile__
с пробелом
__asm__ __volatile__

21 декабря 2024, 23:53:12
#include <stdio.h>

int main(void) {
 int foo=10, bar=15;

 __asm__ __volatile__("addl %%ebx, %%eax"
 : "=a"(foo)
 : "a"(foo), "b"(bar)
 );
 printf("foo+bar=%d\n", foo);
 return 0;
}

21 декабря 2024, 23:54:00
https://av-assembler.ru/asm/high-level-languages/assembler-gcc.php
суть не в этом... и пробел потерялся при написании поста.

25 декабря 2024, 10:36:53
Удивительно! Но это еще не конец:
Пример запись:
: "a" (foo)
или
"eax" (foo),

якобы одно и тоже... теперь давайте запишем в этой строчке:
: "eax"(foo), "ebx"(bar)// input
два варианта:
: "a"(foo), "b"(bar)// input
и
: "a"(foo), "ebx"(bar)// input

И скомпилируем два разных ф. в двух разных дистрибутивах и запустим получившиеся в результате компиляции четыре файла (два в одном два в другом дистрибутиве):
И скомпилируем два разных ф. в двух разных дистрибутивах и запустим получившиеся в результате компиляции четыре файла (два в одном два в другом дистрибутиве):
Цитировать-----------nano inline.c
#include <stdio.h>

int main(void) {
 int foo=10,bar=15;
 
 __asm__ __volatile__ ("addl %%ebx,%%eax"
 : "=eax"(foo) // ouput
 : "eax"(foo), "ebx"(bar)// input
 : "memory" // modify
 );
 printf("foo+bar=%d\n", foo);
 return 0;
}
------------------
gcc inline.c -o inline

Цитировать-----------nano inline1.c
#include <stdio.h>

int main(void) {
 int foo=10,bar=15;
 
 __asm__ __volatile__ ("addl %%ebx,%%eax"
 : "=eax"(foo) // ouput
 : "a"(foo), "ebx"(bar)// input
 : "memory" // modify
 );
 printf("foo+bar=%d\n", foo);
 return 0;
}
------------------
gcc inline1.c -o inline1

И ! третий вариант (правильный):

Цитировать-----------nano inline0.c
#include <stdio.h>

int main(void) {
 int foo=10,bar=15;
 
 __asm__ __volatile__ ("addl %%ebx,%%eax"
 : "=a"(foo) // ouput
 : "a"(foo), "b"(bar)// input
 : "memory" // modify
 );
 printf("foo+bar=%d\n", foo);
 return 0;
}
--------------
gcc inline0.c -o inline0


Получается четыре разных результата:
Цитировать-----Первый дистрибутив ubuntu24
kol@kol-VirtualBox:~/ASM$ uname -r
6.8.0-51-generic
kol@kol-VirtualBox:~/ASM$ ./inline1
foo+bar=791621423
kol@kol-VirtualBox:~/ASM$ ./inline
foo+bar=-188226302
kol@kol-VirtualBox:~/ASM$ ./inline0
foo+bar=25
-----Второй дистрибутив CentOS 9 Stream
[kol@localhost ASM]$ uname -sr
Linux 5.14.0-542.el9.x86_64
[kol@localhost ASM]$ ./inline1
foo+bar=10
[kol@localhost ASM]$ ./inline
foo+bar=10
[kol@localhost ASM]$ ./inline0
foo+bar=25
---------------------------

Впечатляет?
PSменя впечатляет

25 декабря 2024, 10:40:04
Цитата: dzhoser от 21 декабря 2024, 20:56:16В выходных операндах вы указали "=eax"(foo), что является ошибкой.

где написано что это ошибка?

25 декабря 2024, 10:40:29
Цитироватьруководство по использованию системных вызовов и вводное руководство по использованию встроенного ассемблера в gcc.
Пример:
 __asm__("test %%eax,%%eax", : /* без вывода */ : "a" (foo));
или
 __asm__("test %%eax,%%eax", : /* без вывода */ : "eax" (foo));

25 декабря 2024, 10:45:30
Цитата: dzhoser от 21 декабря 2024, 20:56:16В выходных операндах вы указали "=eax"(foo), что является ошибкой.

Все нормально компилируется и запускается без ошибок:
Цитировать#include <stdio.h>

int main(void) {
 int foo=10,bar=15;

 __asm__ __volatile__ ("addl %%ebx,%%eax"
 : "=eax"(foo) // ouput
 : "a"(foo), "b"(bar)// input
 : "memory" // modify
 );
 printf("foo+bar=%d\n", foo);
 return 0;
}

результат :
Цитироватьkol@kol-VirtualBox:~/ASM$ nano inline1.c
kol@kol-VirtualBox:~/ASM$ gcc inline1.c -o inline1
kol@kol-VirtualBox:~/ASM$ ./inline1
foo+bar=25

25 декабря 2024, 10:58:39
Цитата: Лия от 21 декабря 2024, 18:45:07
Цитата: kol1978 от 21 декабря 2024, 16:34:55__asm____volatile__
с пробелом
__asm__ __volatile__

21 декабря 2024, 23:53:12
#include <stdio.h>

int main(void) {
 int foo=10, bar=15;

 __asm__ __volatile__("addl %%ebx, %%eax"
 : "=a"(foo)
 : "a"(foo), "b"(bar)
 );
 printf("foo+bar=%d\n", foo);
 return 0;
}

21 декабря 2024, 23:54:00
https://av-assembler.ru/asm/high-level-languages/assembler-gcc.php
Вот специально создал эту ошибку (т.е. на неё ругается gcc и с ней скомпилировать просто не получилось бы!) :
Цитировать
Цитировать6 |  __asm____volatile__ ("addl %%ebx,%%eax"
      |  ^~~~~~~~~~~~~~~~~~~
inline1.c:6:41: error: expected ')' before ':' token
    6 |  __asm____volatile__ ("addl %%ebx,%%eax"
      |                      ~                  ^
      |                                         )
    7 |  : "=eax"(foo) // ouput
      |  ~   

25 декабря 2024, 11:10:21
Цитата: Лия от 21 декабря 2024, 18:45:0721 декабря 2024, 23:54:00
https://av-assembler.ru/asm/high-level-languages/assembler-gcc.php
к стати по ссылке с Автором можно поспорить "Если наша инструкция изменяет память в непредсказуемом месте, надо добавить "memory" в список используемых регистров." ...там речь не про регистры а вообще про данные и притом данные которые меняются при выполнении процедуры но не указанны не в ходных не в выходных т.е. о которых gcc не может знать совсем. И тут нужен был быть хороший пример коего автор избежал... В приведённом мной примере, указание "memory" может менять "суть" ошибки но по факту в этом ("memory") нет необходимости - все изменяемые данные указаны во входе/выходе. 


dzhoser

#5
Я думаю, что синтаксис ограничений регистров в какой-то момент изменился, но это не очень хорошо задокументировано. Поэтому  "=eax"(foo) в Debian является ошибкой. Неплохо бы было сравнить версии компиляторов.
Тут https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html есть подробное описание того, как параметры передаются в инструкцию asm. Вкратце, это означает, что bar помещается в регистр ebx, foo помещается в eax, и после выполнения инструкции asm в eax будет содержаться обновлённое значение для foo.

Подробнее  тут https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
Как работает mul https://www.aldeid.com/wiki/X86-assembly/Instructions/mul
Ubuntu->Linux mint->Astra Linux SE->Debian 12
Для новичков

kol1978

#6
Цитата: dzhoser от 25 декабря 2024, 10:26:10Я думаю, что синтаксис ограничений регистров в какой-то момент изменился, но это не очень хорошо задокументировано. Поэтому  "=eax"(foo) в Debian является ошибкой. Неплохо бы было сравнить версии компиляторов.
Тут https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html есть подробное описание того, как параметры передаются в инструкцию asm. Вкратце, это означает, что bar помещается в регистр ebx, foo помещается в eax, и после выполнения инструкции asm в eax будет содержаться обновлённое значение для foo.

Подробнее  тут https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
Как работает mul https://www.aldeid.com/wiki/X86-assembly/Instructions/mul
Спасибо за ссылки...мне их приводили на других ф-ах, но все равно спасибо.
По ссылке указан пример
Цитироватьint src = 1;
int dst;

asm ("mov %1, %0\n\t"
 "add $1, %0"
 : "=r" (dst)
 : "r" (src));

printf("%d\n", dst);
в котором есть доп. инструкция mov, которая на мой взгляд нужна...но есть масса примеров где она опускается и указывается конкретный регистр а не абы какой - то есть вроде как это допускается... но на деле, видно что нет - это каша. Если/когда синтаксис asm вставок изменится, вы считаете будет переписан весь ассемблерный код ядра?
Мало того - указанный код тоже не правильный, так как в том случае "абы какой" регистр является входом/выходом и это нужно явно указывать: : "%0" (src)); вместо : "r" (src));... плохо документировано - ну допустим что есть то есть, но суть то в другом: компилируется по разному. Плюсом сравните с тем что "выдает" болт(https://godbolt.org) - и там тоже отличия от реального компилятора/ассемблера. Вот поэтому "статью" назвал - диверсией :( что то вроде - двойные стандарты. :D

29 декабря 2024, 13:56:58
Цитата: ogost от 25 декабря 2024, 06:27:42@kol1978 уберите код под тэг "код".
Сплошная морока вам сюда писать...а править вообще - звиздец. было бы ради чего...

29 декабря 2024, 09:00:37
Цитата: dzhoser от 25 декабря 2024, 10:26:10Поэтому  "=eax"(foo) в Debian является ошибкой.
Откуда вы это взяли...???

29 декабря 2024, 09:04:52
Цитата: dzhoser от 25 декабря 2024, 10:26:10Неплохо бы было сравнить версии компиляторов.
Вы считаете что синтаксис gcc в части asm и "ограничени" регистров, вставок в некой версии уже изменился и именно это влияет на результат?

dzhoser

#7
Цитата: kol1978 от 29 декабря 2024, 08:48:06Сплошная морока вам сюда писать...а править вообще - звиздец. было бы ради чего...
Ради удобства других.
Цитата: kol1978 от 29 декабря 2024, 08:48:06Откуда вы это взяли...???
Из вашего примера, так как возвращается неверный результат, следовательно и не правильный синтаксис.
Цитата: kol1978 от 29 декабря 2024, 08:48:06Вы считаете что синтаксис gcc в части asm и "ограничении" регистров, вставок в некой версии уже изменился и именно это влияет на результат?
Да.
Ubuntu->Linux mint->Astra Linux SE->Debian 12
Для новичков

kol1978

#8
Из вашего примера, так как возвращается неверный результат, следовательно и не правильный синтаксис.
Цитата: kol1978 от 29 декабря 2024, 08:48:06Вы считаете что синтаксис gcc в части asm и "ограничении" регистров, вставок в некой версии уже изменился и именно это влияет на результат?
Да.
[/quote] Не правильный синтаксис приводит к ошибке компиляции и соответствующим сообщениям о ошибке, таковых не было поэтому это заявление огульно и не чем не подкреплено. Так же речь шла именно о debian и может трактоваться, что это распространяется только на этот дистрибутив - что опять же ни чем не подкреплено.
"неверный результат, следовательно и не правильный синтаксис" - с логикой прям беда, одно из другого не следует...

30 декабря 2024, 23:20:10
Похоже выяснил причину "ошибки" - это действительно ошибка компилятора, а не измененного синтаксиса или версии или чего еще...
И так (доказательства)! вот код : 
Цитировать--------------------------------nano add_aab.c

#include <stdio.h>

int main(void) {
 int foo=10,bar=15;
 
 __asm__ __volatile__ (
   "add eax, ebx;\n\t"
   : "=a"(foo) // ouput
   : "a"(foo), "b"(bar)// input
   : "memory" // modify
 );
 printf("foo+bar=%d\n", foo);
 return 0;
}
------------------------------

30 декабря 2024, 23:22:29
компилируем его :
Цитироватьgcc -std=c99 -Os -m64 -fno-asynchronous-unwind-tables -fno-dwarf2-cfi-asm -Wall -S -masm=intel add_aab.c -o add_aab.s

gcc -Wall -masm=intel add_aab.s -o add_aab
Смотрим :
Цитироватьcat add_aab.s
-----------------------------------получается
   .file   "add_aab.c"
   .intel_syntax noprefix
   .text
   .section   .rodata.str1.1,"aMS",@progbits,1
.LC0:
   .string   "foo+bar=%d\n"
   .section   .text.startup,"ax",@progbits
   .globl   main
   .type   main, @function
main:
   push   rbx
   mov   eax, 10
   mov   ebx, 15
#APP
# 7 "add_aab.c" 1
   add eax, ebx;
# 0 "" 2
#NO_APP
   lea   rdi, .LC0[rip]
   mov   esi, eax
   xor   eax, eax
   call   printf@PLT
   xor   eax, eax
   pop   rbx
   ret
   .size   main, .-main
   .ident   "GCC: (Debian 10.2.1-6) 10.2.1 20210110"
   .section   .note.GNU-stack,"",@progbits
---------------------------------------------------------https://godbolt.org/
.LC0:
        .string "foo+bar=%d\n"
main:
        push    rbx
        mov     eax, 10
        mov     ebx, 15
        add eax, ebx;

        mov     edi, OFFSET FLAT:.LC0
        mov     esi, eax
        xor     eax, eax
        call    printf
        xor     eax, eax
        pop     rbx
        ret
--------------------------------------------------------

30 декабря 2024, 23:23:42
Видим что перед вызовом ф. printf применяются две инструкции :
Цитироватьlea   rdi, .LC0[rip]
   mov   esi, eax


30 декабря 2024, 23:27:20
mov   esi, eax  - это самая важная...см. дальше
Используем код :
Цитировать--------------------------------------------nano add_rrr.c
#include <stdio.h>

int main(void) {
 int foo=10,bar=15;
 __asm__ __volatile__ (
        "add %0, %2;\n\t"
        : "=r"(foo) // ouput
        : "r"(foo), "r"(bar)// input
        : "memory" // modify
 );
 printf("foo+bar=%d\n", foo);
 return 0;
}
--------------------------------------------------------------правильно просто "случайно"
   .file   "add_rrr.c"
   .intel_syntax noprefix
   .text
   .section   .rodata.str1.1,"aMS",@progbits,1
.LC0:
   .string   "foo+bar=%d\n"
   .section   .text.startup,"ax",@progbits
   .globl   main
   .type   main, @function
main:
   mov   esi, 10
   push   rax
   mov   eax, 15
#APP
# 5 "add_rrr.c" 1
   add esi, eax;
# 0 "" 2
#NO_APP
   lea   rdi, .LC0[rip]
   xor   eax, eax
   call   printf@PLT
   xor   eax, eax
   pop   rdx
   ret
   .size   main, .-main
   .ident   "GCC: (Debian 10.2.1-6) 10.2.1 20210110"
   .section   .note.GNU-stack,"",@progbits
---------------------------------------------------------------
gcc -std=c99 -Os -m64 -fno-asynchronous-unwind-tables -fno-dwarf2-cfi-asm -Wall -S -masm=intel add_rrr.c -o add_rrr.s

gcc -Wall -masm=intel add_rrr.s -o add_rrr
cat add_rrr.s
И! видим что в этом коде этой инструкции (mov   esi, eax)почему то нет! Но! код выполняется верно просто потому что регистр esi загружен результатом при выполнении операции  add esi, eax (из вставки)!

30 декабря 2024, 23:29:46
Изменяем немного код (что бы уйти от случайности)?
Цитировать--------------------------------------------nano add_rab.c
#include <stdio.h>

int main(void) {
 int foo=10,bar=15;
 __asm__ __volatile__ (
        "add %1, %2;\n\t"
        : "=r"(foo) // ouput
        : "a"(foo), "b"(bar)// input
        : "memory" // modify
 );
 printf("foo+bar=%d\n", foo);
 return 0;
}
------------------------------------------
Этот код работает не верно просто из за отсутствий необходимой инструкции при вызове ф. printf!

30 декабря 2024, 23:32:00
Убеждаемся путём правки ассемблерного кода :
Цитировать--------------------------foo+bar=62218488 
   .file   "add_rab.c"
   .intel_syntax noprefix
   .text
   .section   .rodata.str1.1,"aMS",@progbits,1
.LC0:
   .string   "foo+bar=%d\n"
   .section   .text.startup,"ax",@progbits
   .globl   main
   .type   main, @function
main:
   push   rbx
   mov   eax, 10
   mov   ebx, 15
#APP
# 5 "add_rab.c" 1
   add eax, ebx;
# 0 "" 2
#NO_APP
   lea   rdi, .LC0[rip]
   xor   eax, eax
   call   printf@PLT
   xor   eax, eax
   pop   rbx
   ret
   .size   main, .-main
   .ident   "GCC: (Debian 10.2.1-6) 10.2.1 20210110"
   .section   .note.GNU-stack,"",@progbits

-----------------------------------------------
gcc -std=c99 -Os -m64 -fno-asynchronous-unwind-tables -fno-dwarf2-cfi-asm -Wall -S -masm=intel add_rab.c -o add_rab.s

gcc -Wall -masm=intel add_rab.s -o add_rab
cat add_rab.s

-------------------https://godbolt.org/
.LC0:
        .string "foo+bar=%d\n"
main:
        push    rbx
        mov     eax, 10
        mov     ebx, 15
        add eax, ebx;

        mov     edi, OFFSET FLAT:.LC0
        xor     eax, eax
        call    printf
        xor     eax, eax
        pop     rbx
        ret
-------------------------------------#     моя правка
   .file   "add_rab.c"
   .intel_syntax noprefix
   .text
   .section   .rodata.str1.1,"aMS",@progbits,1
.LC0:
   .string   "foo+bar=%d\n"
   .section   .text.startup,"ax",@progbits
   .globl   main
   .type   main, @function
main:
   push   rbx
   mov   eax, 10
   mov   ebx, 15
#APP
# 5 "add_rab.c" 1
   add eax, ebx
# 0 "" 2
#NO_APP
   mov     esi, eax        #        моя правка      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   lea   rdi, .LC0[rip]
   xor   eax, eax
   call   printf@PLT
   xor   eax, eax
   pop   rbx
   ret
   .size   main, .-main
   .ident   "GCC: (Debian 10.2.1-6) 10.2.1 20210110"
   .section   .note.GNU-stack,"",@progbits

-----------------------------------------------

30 декабря 2024, 18:36:20
Ну всЕ! двайте мне медаль!  ;D  :D  ;)

30 декабря 2024, 18:40:10
PS
Цитировать-----------------------------------------------
#include <stdio.h>

int main(void) {
 int foo=10,bar=15;
 printf("foo+bar=%d\n", foo);
 return 0;
}
---------------------------------https://godbolt.org/
.LC0:
        .string "foo+bar=%d\n"
main:
        push    rax
        mov     esi, 10             # эту инструкция компилятор "забывает" вставить! перед вызовом printf
        mov     edi, OFFSET FLAT:.LC0
        xor     eax, eax
        call    printf
        xor     eax, eax
        pop     rdx
        ret
---------------------------------------------