Запись строки в память

Учусь работать с отладчиком GDB - разбираю пример простой программы на языке C. Пример из учебника, так что не ругайтесь за код. Тем более что вопрос по компиляции/ассемблеру.

#include <stdio.h>
#include <string.h>

int main( )
{
    char str_a[20];
    strcpy(str_a, "Hello, world!\n");
    printf(str_a);
}

Компилировал gcc 11.1.0 с флагами -g -no-pie .
Дизассемблированный код в интересующем меня месте выглядит так:

...
<main+27>:  lea    rax                 , [rbp-0x20]
<main+31>:  movabs rcx                 , 0x77202c6f6c6c6548
<main+41>:  mov    QWORD PTR [rax]     , rcx
<main+44>:  mov    DWORD PTR [rax+0x8] , 0x646c726f
<main+51>:  mov    WORD  PTR [rax+0xc] , 0xa21
<main+57>:  mov    BYTE  PTR [rax+0xe] , 0x0
...

Пример полного дизассемблера можно посмотреть на godbolt здесь. Он чуть отличается от того, что у меня gdb выдает, но приведенная часть аналогичная.

Вопрос такой: почему первые 8 байт записываются в память в две инструкции <main+31>, <main+41> через использование регистра rcx , а оставшиеся 7 байт записываются напрямую? Могу понять, почему, к примеру, ради 1 байта нуль-терминатора нецелесообразно целый регистр какой-нибудь задействовать. Но почему в таком случае и первые 8 байт тоже не записываются напрямую по подобию других?

***** UPDATE *****

Спасибо @Fat-Zer за ответ. Действительно, нет такой инструкции, которая бы напрямую пересылала 64-битный константный аргумент в память. Сверился по мануалу Intel (для инструкции mov можно посмотреть Vol. 2B 4-35)

Также благодарность за комментарий @Илья К, который указал на существующее ограничения максимальной длины инструкции в 15 байт.


Ответы (1 шт):

Автор решения: Fat-Zer

Но почему в таком случае и первые 8 байт тоже не записываются напрямую по подобию других?

В наборе команд amd64 банально нет инструкции, пересылающей 64-х-битный константный аргумент команды (в отличии от 32-х-битных и меньше) напрямую в память. Поэтому приходится помещать его сначала в регистр, и только потом сохранить в память.

А две инструкции записывающие по 4 байта сразу в память, как подметил @avp, занимали бы, как минимум, просто больше места: 14 байт против 13, хотя, возможно, у компилятора были и какие-то другие причины так сделать.

Почему именно такой инструкции нет — стоит спросить у инженеров AMD. Как подсказывает @ИльяК, одна из причин, почему такой команды нет, вероятно, в том, что для некоторых типов адресации она получилось бы слишком большой: 8 байт на адрес и 8 байт на аргумент + собственно опкод, что не поместилось бы, в частности, в 128-ми битную шину предекодера инструкций на K8.

→ Ссылка