Это просто невезение.
GCC 8, без оптимизаций , использует rax
в качестве промежуточного местоположения для перемещения argv[1]
в bob
и перемещения последнего в первый параметр strlen
:
push rbp
mov rbp, rsp
sub rsp, 32
mov DWORD PTR [rbp-20], edi ;argc
mov QWORD PTR [rbp-32], rsi ;argv
mov rax, QWORD PTR [rbp-32] ;argv
mov rax, QWORD PTR [rax+8] ;argv[1]
mov QWORD PTR [rbp-8], rax ;bob = argv[1]
mov rax, QWORD PTR [rbp-8]
mov rdi, rax
call strlen ;strlen(bob)
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
leave
ret
Это просто невезение, это не задокументированное поведение, на самом деле произойдет сбой, если вы используете строковый литерал :
printf("%i\n", strlen("bob"));
mov edi, OFFSET FLAT:.LC1
call strlen ;No RAX here
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
Документ, определяющий, какчтобы параметры передавались в функцию вашей операционной системы ABI, читайте больше в этом ответе .
GCC генерирует «тупой» код, который часто использует регистры, когда оптимизация отключена,это облегчает отладку (как движка GCC, так и скомпилированной программы) и по существу имитирует новичков: сначала переменная считывается из памяти и помещается в первый свободный регистр (одна проблема решена), затем она копируется в правильный регистр (еще один пропал) и, наконец, вызов сделан.
GCC только что подобрал первый свободный регистр, в этой простой программе нет давления регистров, и rax
всегда поднимается.