Estoy analizando un fragmento de código ineficiente, pero parte de él es tan confuso.
Codigo original:
#include <string.h> void lowwer(char *str) { for (int i = 0; i < strlen(str); ++i) { str[i] -= ('A' - 'a'); } }Código ensamblador (generado por clang 13 con la opción -Og):
lowwer: pushq %r14 # use saved-registers pushq %rbx pushq %rax # guard do while cmpb $0, (%rdi) # compare &str with null (check if strlen(str) == 0) je .LBB0_3 # loop initialization movq %rdi, %r14 # %r14 = str xorl %ebx, %ebx # clear %rbx (for more compact encoding) .LBB0_2: # =>This Inner Loop Header: Depth=1 addb $32, (%r14,%rbx) # subtract -32 from str[i] ('A' - 'a' = -32) addq $1, %rbx # ++i movq %r14, %rdi # seems meaningless here? callq strlen@PLT cmpq %rbx, %rax # check i < strlen(str) ja .LBB0_2 .LBB0_3: # end addq $8, %rsp # ??? popq %rbx # free registers popq %r14 retqmovq %r14, %rdi ? Parecía sin sentido porque %r14 sosteniendo el puntero de cadena y el rdi es lo mismo.addq $8, %rsp . Parece despistado.rdi es un registro guardado por la persona que llama y, por lo tanto, la llamada a strlen lo desecha. Para preservar su contenido, el compilador emitió código para mover su contenido a r14 , copiándolo una vez cada iteración como argumento para strlen .
La addq $8, %rsp libera espacio de pila previamente asignado por pushq %rax . Este espacio de pila se asignó para satisfacer los requisitos de alineación de pila impuestos por amd64 SysV ABI.
Consulte el suplemento amd64 SysV ABI para conocer la convención de llamadas completa y una lista de registros guardados de llamantes/llamados.