Столкнуться с необходимостью такого сравнения можно в любой программе, принимающей входные данные от пользователя, например авторизация. Для этого существует специальная инструкция сравнения строк - cmpsb, она берет данные из регистров %esi, %edi и %ecx:
------------------------------------------------------------------------- /* strcmp.s */ .globl _start _start: movl $str1,%esi # кладем первую строку в %esi movl $str2,%edi # вторую в %edi movl $4,%ecx # количество байт для сравнения cld # очистить флаг D, иначе сравнение # пойдет в обратном порядке rep cmpsb # сравнение jz yes # если строки равны то прыгаем в yes, # если нет, то exit exit: movl $1,%eax # выход int $0x80 yes: movl $4,%eax # write movl $1,%ebx # stdout movl $msg,%ecx # наше сообщение movl $msglen,%edx # его длина int $0x80 jmp exit .data str1: .string "asdf" str2: .string "asdf" msg: .string "The strings are equal! Quiting...\n" msglen = . -msg # вычислить длину msg /* End */ -------------------------------------------------------------------------
as strstr.s -o strstr.o
ld strstr.o
------------------------------------------------------------------------- /* strcat.s */ .globl main main: movl $str1,%esi # кладем строку "AT&T" в %esi movl $buf,%edi # буфер с будущим результатом movl $6,%ecx # размер стринга cld rep movsb # после выполнения в $buf находится str1 movl $str2,%esi # далее производим выше описаные операции с str2 movl $9,%ecx cld rep movsb # вуаля, теперь у нас в $buf имеется str1+str2, # т.е "AT&T is cool\n" movl $4,%eax # write movl $1,%ebx # stdout movl $buf,%ecx # "AT&T is cool\n" movl $15,%edx # size of $buf int $0x80 movl $1,%eax # exit int $0x80 .data str1: .string "AT&T " str2: .string "is cool\n" buf: .byte 15 # static buffer /* End */ -------------------------------------------------------------------------
------------------------------------------------------------------------- /* counter.s */ .globl main main: movl $5,%esi # число повторений , используй %esi или %edi не важно loop: # write (stdout,str,5); movl $4,%eax movl $1,%ebx movl $str,%ecx movl $5,%edx int $0x80 decl %esi # уменьшить %esi на 1 tesl %esi,%esi # если %esi 0 jz exit # jmp exit jmp loop # прыжок на начало exit: movl $1,%eax int $0x80 /* End */ -------------------------------------------------------------------------
Для реализации этой функции мы прибегнем к небольшому трюку. Будем использовать инструкцию lodsb для проверки строки байт за байтом, попутно увеличивая счетчик для вычисления длины. Сперва необходимо поместить эфективный адрес строки в %esi, %edi будет счетчиком.
------------------------------------------------------------------------- /* strlen.s */ .globl main main: xorl %edi,%edi leal str,%esi # эфективный адрес в %esi abc: lodsb # читает байт в строке и автоматически устанавливает # следующую позицию cmpb $0,%al # если байт равен 0, значит end of string jz continue incl %edi # счетчик jmp abc # повторить... continue: decl %edi ... # в %edi готовый результат - длина (int) .data str: .string "CheckMylength" # если в строке присутствует \n, длина увеличивается # дополнительно на 1 байт /* End */ -------------------------------------------------------------------------
Но не забывай ! Это постоянные (статические) переменные, устанавливающиеся во время компиляции. В итоге невозможно увеличить\уменьшить их в коде. К этому методу можно прибегнуть если большой код расчитан на анализ другими людьми, в таком случае осмысленные названия будут более понятны при изучении. [ Continue... ]
------------------------------------------------------------------------- /* Small C example */ int main() { char a[10]; int b; for (b=0;b!=10;b++) { a[b]='a'; printf("%c",a[b]); } } /* End */ -------------------------------------------------------------------------
------------------------------------------------------------------------- /* array.s */ count = 10 # счетчик a = -12 # смещение в %ebp, место для нашего массива - # как char a[10]; b = -16 # int b; char = 97 # символ 'a' (dec) sysint = 0x80 .globl main main: movl $0,b(%ebp) # for(b=0; loop: cmpl $count,b(%ebp) # b != 10; jnz lp # jump if not equal jmp exit # jump if counter reached lp: leal a(%ebp),%edi # a[ movl b(%ebp),%esi # b] movb $char,(%esi,%edi) # ='a'; incl b(%ebp) # b++); # write(stdout,a[b],1); movl $4,%eax movl $1,%ebx leal (%esi,%edi),%ecx movl $1,%edx int $sysint jmp loop exit: movl $1,%eax int $sysint /* End */ -------------------------------------------------------------------------
Как можно заметить, область массива в %edi и его элементы в %esi, готовый массив находится в (%esi,%edi).
Для чего это надо ? Например syscall write работает только со строками, и если мы сделаем write(stdout,numeric,length), будет выдан символ из ASCII таблицы с номером numeric. Числа в ASCII таблице начинаются с 48 (decimal 0), поэтому мы просто увеличиваем наш numeric на 48 и получаем аскишный эквивалент необходимой цифры. Перед тем как выполнить это на асме, взглянем на процедуру выполненную в С...Так как система счисления десятеричная, то соответственно и делить необходимо на 10:
------------------------------------------------------------------------- /* num2ascii.c */ int main() { char a[10]; int x = 1234,b=0; do // отделяем каждую цифру от целого числа { a[b]=48 + x % 10; // кладем в массив, первый элемент содержит "4", второй "3" // etc... - обратный порядок b++; } while (x /= 10); do // перевернем 4321 в необходимое 1234 { b--; printf("%d\n",a[b]); } while(b!=0); } /* End */ -------------------------------------------------------------------------
------------------------------------------------------------------------- /* num2ascii.s */ int = 1234 .globl main main: xorl %esi,%esi movl $int,%eax loop: movl $0,%edx movl $10,%ebx divl %ebx # деление, результат в %eax (123) и остаток в %edx (4) addb $48,%dl # +48 pushl %edx # на стек incl %esi # счетчик цифр cmpb $0,%al jz next jmp loop next: popl (%ecx) # взять со стека testl %esi,%esi jz exit decl %esi movl $4,%eax movl $1,%ebx movl $2,%edx int $0x80 jmp next exit: movl $1,%eax int $0x80 /* End */ -------------------------------------------------------------------------
------------------------------------------------------------------------- /* htons.s */ int = 10 .globl main main: movl $int,%edi movl %edi,%eax rol $8,%ax # сдвиг, rol или ror здесь роли не играют # сейчас %eax содержит 10 в nbo ... /* End */ -------------------------------------------------------------------------