Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 Languages
 С
 GNU С Library 
 Qt 
 STL 
 Threads 
 C++ 
 Samples 
 stanford.edu 
 ANSI C
 Libs
 LD
 Socket
 Pusher
 Pipes
 Encryption
 Plugin
 Inter-Process
 Errors
 Deep C Secrets
 C + UNIX
 Linked Lists / Trees
 Asm
 Perl
 Python
 Shell
 Erlang
 Go
 Rust
 Алгоритмы
NEWS
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 Linux Kernel 2.6...3653 
 Trees...489 
 Clickhouse...460 
 Go Web ...455 
 Ethreal 4...452 
 Максвелл 3...420 
 Ext4 FS...412 
 C++ Patterns 3...402 
 Rodriguez 6...397 
 William Gropp...390 
 Ethreal 1...385 
 Secure Programming for Li...382 
 Steve Pate 1...381 
 Gary V.Vaughan-> Libtool...380 
 Ethreal 3...371 
 Assembler...361 
 DevFS...359 
 Стивенс 9...353 
 Ulrich Drepper...348 
 Стивенс 10...324 
 
  01.01.2024 : 3621733 посещений 

iakovlev.org

AT&T Tutorial

[1]. Как сравнить 2 строковые переменные ?:

Столкнуться с необходимостью такого сравнения можно в любой программе, принимающей входные данные от пользователя, например авторизация. Для этого существует специальная инструкция сравнения строк - 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
Можно использовать gcc: gcc strstr.s , предварительно заменив "_start" на "main".

[2]. Как соединить строковые переменные ?:

Для этого будем использовать интсрукцию movsb, первую строку кладем в %esi и буфер, в котором получим результат, в %edi. Взгляни на пример:
-------------------------------------------------------------------------
 /* 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 */
 ------------------------------------------------------------------------- 
 

[3]. Как создать счетчик ?:

Что за программа без счетчика ? Да, счетчик часто используемая функция. Для визуальной демонстрации работы нашего счетчика будет использован вывод строки через write, поэтому регистры %eax,%ebx,%ecx,%edx будут заняты, но %esi и %edi останутся, их-то мы и будем использовать:
-------------------------------------------------------------------------
 /* 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 */
 ------------------------------------------------------------------------- 
 

[4]. Как динамически вычислить длину строки ?:

Для реализации этой функции мы прибегнем к небольшому трюку. Будем использовать инструкцию 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 */
 ------------------------------------------------------------------------- 
 
Небольшой перерыв для нескольких советов. Почему бы не использовать переменные в более дружественном виде ? int $sysint - выглядит лучше чем int $0x80, объявляется это так - sysint = 0x80, все что захочешь:
int = 1
char = 97 # character "a"
(dec) char = 0x61 # character "a" (hex)
etc...

Но не забывай ! Это постоянные (статические) переменные, устанавливающиеся во время компиляции. В итоге невозможно увеличить\уменьшить их в коде. К этому методу можно прибегнуть если большой код расчитан на анализ другими людьми, в таком случае осмысленные названия будут более понятны при изучении.

[ Continue... ]

[5]. Как работать с массивами ?:

 -------------------------------------------------------------------------
 /* Small C example */
 int main()
 {
 char a[10];
 int b; for (b=0;b!=10;b++)
  {
   a[b]='a';
   printf("%c",a[b]);
  }
 }
 /* End */
 ------------------------------------------------------------------------- 
 
 
Этот пример пихает символ "a" в каждый элемент массива, вывод программы выглядит так:aaaaaaaaaa На мой взгляд это подходящий пример.
-------------------------------------------------------------------------
 /* 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).

[6]. Как сконвертировать число(integer) в его ASCII эквивалент(string)?:

Для чего это надо ? Например 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 */
 -------------------------------------------------------------------------
 
Это приблизительная реализация, если перевести ее шаг за шагом на асм, мы получим большой код в пределах ~1kb, поэтому пример на асме имеет немного другую структуру.
-------------------------------------------------------------------------
 /* 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 */
 -------------------------------------------------------------------------  
 
 

[7]. Как сконвертировать числовую переменную в сетевой байтовый порядок (network byte order) ?:

Такая нужда у нас появляется при работе с сокетами, а точнее htons(port).
-------------------------------------------------------------------------
 /* htons.s */
 int = 10
 .globl main
 main: 
 movl $int,%edi
 movl %edi,%eax
 rol $8,%ax  # сдвиг, rol или ror здесь роли не играют 
 
 # сейчас %eax содержит 10 в nbo
 ... /* End */
 ------------------------------------------------------------------------- 
 
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье