Может кто-нибудь объяснить эту программу на ассемблере, чтобы найти обратную строку? Используется ли RAX неинициализированным после read ()? - PullRequest
0 голосов
/ 10 ноября 2019
%macro read 1
Mov ax,3
mov bx,0
mov rcx,%1
mov dx,20
Int 80h
%endmacro

%macro print 2
Mov ax,4
mov bx,1
mov rcx,%1
mov dx,%2
Int 80h
%endmacro  

 section .Data
           len : db 0
   section .bss
       Str1 resb 20
       Str2 resb 20
   section .text
     global _start: 
          read str1 ;using macro
      mov [len],al
      lea rsi,[str1]
      lea rdi,[str2]
      mov rcx,rax
      dec rcx
      Add rsi,rcx
 loop1:
       Dec rsi
       Mov al,[rsi]
       Mov [rdi],al
       Inc rdi
       loop loop1
       print str2,[len]

     Exit: 
        mov ax,1
        Mov bx,0
        int 80h


С помощью приведенного выше кода asm я могу найти обратную строку. Но здесь после чтения строковый регистр Al перемещается в len Но Регистр Al не инициализируется и какие данные хранятся в rcx, rax ?

Может кто-нибудь просто объяснить приведенный выше код?

1 Ответ

0 голосов
/ 10 ноября 2019

Довольно очевидно, read возвращает длину в RAX. Это абсолютно нормально для функций и имеет смысл и для макроса.

В этом случае, да, это просто (глючная) оболочка вокруг 32-битного int 0x80 ABI для read(), который, как объясняет man-страница, возвращает длину. Системные вызовы Linux возвращаются в RAX. Он также странным образом жестко кодирует максимальную длину как 20.

(он глючит, потому что работает только в том случае, если EAX, EBX и EDX уже равны нулю. Он записывает только младшие 16 битов этих регистров перед вызовом 32-битный ABI. Запись полного RCX с адресом бесполезна; int 0x80 использует только младшие 32 бита. Что произойдет, если вы используете 32-битный int 0x80 Linux ABI в 64-битном коде? )

AL - младший байт RAX, и этот код сохраняет только младший байт длины для печати. ИДК почему они сохраняют его в памяти вместо другого регистра, как нормальный человек. Особенно, когда они копируют всю 64-битную длину в RCX вместо обычного mov ecx, eax для расширения нуля 32-битного значения в RCX.


Также обратите внимание, что позднее mov ax,1 (32-бит __NR_exit) рискованно и плохая идея;он потенциально оставляет мусор в старших байтах RAX, приводя к -ENOSYS вместо _exit(0),

При небольшом размере буфера чтение приведет к ошибке (или вернет -EFAULT, прежде чем он сможет вернуть больше, чем 4096, поэтомув этом случае безопасна замена только младших 16 битов RAX.

Если read не возвращает отрицательный код ошибки, то эта программа будет аварийно завершать работу вместо выхода, когда последний int 0x80 вернет -ENOSYS вместовыход.

Попробуйте запустить его с ./a.out <&-, чтобы закрыть стандартный ввод, приводя к -EBADF для чтения из стандартного ввода, , а затем сбой.

Кроме того, это64-битный код, поэтому использование 32-битного int 0x80 системного вызова Linux ABI не очень хорошая идея. Некоторые системы Linux (включая WSL) не имеют CONFIG_IA32_EMULATION и просто ошибаются, как если бы они int 0x81 или любое другое программное прерывание. Что произойдет, если вы используете 32-битный int 0x80 Linux ABI в 64-битном коде?

...