LINUX.ORG.RU

История изменений

Исправление cudeta, (текущая версия) :

что именно Вы бы написали по-другому?

Это бездарный мусор, который наглядно демонстрирует, зачем нужен компилятор.

mov rdx, 0 ; Automatic protocol.

xor rdx, rdx — рекомендованный Intel и AMD способ занулить регистр. Это называется zero idiom, оно занимает меньше места, чем mov rdx, 0 и распознаётся на уровне декодирования инструкций.

cmp rax, 0

test rax, rax занимает меньше места и выставляет те же флаги.

cld ; Move forward
mov ecx, 19 ; Length is 19 with the null terminator.
rep movsb ; Copy.

Это гораздо медленнее, чем тупо скопировать через mov 8+8+2+1 байт.

lea rsi, [rsp]

mov rsi, rsp

imul rax, 8 ; sizeof(format) == 8

В этом контексте (флаги не проверяются) эквивалентно shl rax, 3 либо (в синтаксисе AT&T, не силён в интеловском) leaq (,8,%rax), %rax.

  mov BYTE [rsp + 3*4 + 0], 'f'
  mov BYTE [rsp + 3*4 + 1], 'i'
  mov BYTE [rsp + 3*4 + 2], 'x'
  mov BYTE [rsp + 3*4 + 3], 'e'
  mov BYTE [rsp + 3*4 + 4], 'd'

Зачем, если можно через два mov это сделать?

  ; Compute padding and packet u32 count with division and modulo 4.
  mov eax, edx ; Put dividend in eax.
  mov ecx, 4 ; Put divisor in ecx.
  cdq ; Sign extend.
  idiv ecx ; Compute eax / ecx, and put the remainder (i.e. modulo) in edx.
  ; LLVM optimizer magic: `(4-x)%4 == -x & 3`, for some reason.
  neg edx
  and edx, 3 
  mov r9d, edx ; Store padding in r9.

Особая одарённость, сложно это даже как-то прокомментировать.

  cld ; Move forward
  mov ecx, r8d ; String length.
  rep movsb ; Copy.

Это очень неоптимально, см. как реализован memcpy в glibc.

  ; Read the server response: read(2).
  ; Use the stack for the read buffer.
  ; The X11 server first replies with 8 bytes. Once these are read, it replies with a much bigger message.
  mov rax, SYSCALL_READ
  mov rdi, rdi
  lea rsi, [rsp]
  mov rdx, 8
  syscall

  cmp rax, 8 ; Check that the server replied with 8 bytes.
  jnz die
  ; Read the rest of the server response: read(2).
  ; Use the stack for the read buffer.
  mov rax, SYSCALL_READ
  mov rdi, rdi
  lea rsi, [rsp]
  mov rdx, 1<<15
  syscall
  
  cmp rax, 0 ; Check that the server replied with something.
  jle die

SOCK_STREAM так не работает.

Note: There is an optimization method that uses rbp as a standard register (with a C compiler, that’s the flag -fomit-frame-pointer), which means we lose the information about the call stack. My advice is: never do this, it is no worth it.

-fomit-frame-pointer это умолчание на x86-64.

Исходная версия cudeta, :

что именно Вы бы написали по-другому?

Это бездарный мусор, который наглядно демонстрирует, зачем нужен компилятор.

mov rdx, 0 ; Automatic protocol.

xor rdx, rdx — рекомендованный Intel и AMD способ занулить регистр. Это называется zero idiom, оно занимает меньше места, чем mov rdx, 0 и распознаётся на уровне декодирования инструкций.

cmp rax, 0

test rax, rax занимает меньше места и выставляет те же флаги.

cld ; Move forward
mov ecx, 19 ; Length is 19 with the null terminator.
rep movsb ; Copy.

Это гораздо медленнее, чем тупо скопировать через mov 8+8+2+1 байт.

lea rsi, [rsp]

mov rsi, rsp

imul rax, 8 ; sizeof(format) == 8

В этом контексте (флаги не проверяются) эквивалентно shl rax, 3.

  mov BYTE [rsp + 3*4 + 0], 'f'
  mov BYTE [rsp + 3*4 + 1], 'i'
  mov BYTE [rsp + 3*4 + 2], 'x'
  mov BYTE [rsp + 3*4 + 3], 'e'
  mov BYTE [rsp + 3*4 + 4], 'd'

Зачем, если можно через два mov это сделать?

  ; Compute padding and packet u32 count with division and modulo 4.
  mov eax, edx ; Put dividend in eax.
  mov ecx, 4 ; Put divisor in ecx.
  cdq ; Sign extend.
  idiv ecx ; Compute eax / ecx, and put the remainder (i.e. modulo) in edx.
  ; LLVM optimizer magic: `(4-x)%4 == -x & 3`, for some reason.
  neg edx
  and edx, 3 
  mov r9d, edx ; Store padding in r9.

Особая одарённость, сложно это даже как-то прокомментировать.

  cld ; Move forward
  mov ecx, r8d ; String length.
  rep movsb ; Copy.

Это очень неоптимально, см. как реализован memcpy в glibc.

  ; Read the server response: read(2).
  ; Use the stack for the read buffer.
  ; The X11 server first replies with 8 bytes. Once these are read, it replies with a much bigger message.
  mov rax, SYSCALL_READ
  mov rdi, rdi
  lea rsi, [rsp]
  mov rdx, 8
  syscall

  cmp rax, 8 ; Check that the server replied with 8 bytes.
  jnz die
  ; Read the rest of the server response: read(2).
  ; Use the stack for the read buffer.
  mov rax, SYSCALL_READ
  mov rdi, rdi
  lea rsi, [rsp]
  mov rdx, 1<<15
  syscall
  
  cmp rax, 0 ; Check that the server replied with something.
  jle die

SOCK_STREAM так не работает.

Note: There is an optimization method that uses rbp as a standard register (with a C compiler, that’s the flag -fomit-frame-pointer), which means we lose the information about the call stack. My advice is: never do this, it is no worth it.

-fomit-frame-pointer это умолчание на x86-64.