Иллюстрированный самоучитель по теории операционных систем

Косвенно-регистровый режим со смещением

Пример 2.4. Формирование, использование и уничтожение стекового кадра. Код на языке С и результат его обработки GNU С 2.7.2.1 (комментарии автора):

#include <stdio.h>
# include <strings.h>
/* Фрагмент примитивной реализации сервера SMTP (RFC822) */
int parse_line(FILE * socket)
{
/* Согласно RFC822, команда имеет длину не более 4 байт,
; а вся строка – не более 255 байт V char cmd[5], args [255];
;fscanf (socket, "%s %s\n", cmd, args);
if (stricmpfcmd, "HELO")==0) {
fprintf (socket, "200 Hello, %s, glad to meet you\n", args);
return 200;
)
/* etc */
fprintf (socket, "500 Unknown command %s\n", cmd);
return 500;
.file "sample" gcc2_compiled.: _ gnu_compiled_c:.text LCO:
.ascii "%s %s\12\0" LCI:
.ascii "HELCAO" LC2:
.ascii "200 Hello, %s, glad to meet you\12\0" LC3:
.ascii "500 Unknown command %s\12\0"
.align 2, 0x90.globl _parse_line _parse_line:
; x86 имеет для этой цели специальную команду enter, но она может
; формировать кадры размером не более 255 байт.
; В данном случае кадр имеет больший размер,
; и его необходимо формировать вручную.
pushl %ebp; Сохраняем указатель кадра
; вызвавшей нас подпрограммы.
movl %esp, %ebp; Формируем указатель нашего кадра
subl $264,%esp; И сам кадр.
; Конец пролога функции
leal -264 (%ebp), %еах; Помещаем в стек указатель на args pushl %eax
leal -8 (%ebp), %еах;… на cmd
pushl %eax
pushl $LCO; на строковую константу
; Наши собственные параметры тоже адресуются относительно кадра
 .movl 8(%ebp),%eax
; Параметр socket мы тоже проталкиваем pushl %eax
; в стек
call fscanf
; Вызов (параметры в стеке) addl $16,%esp
; очищаем стек
; в языке С переменное количество параметров, поэтому вычищать их из
; стека должна вызывающая процедура. Вызываемая просто не знает,
; СКОЛЬКО ИХ бЫЛО.
pushl $LC1
leal -8(%ebp),%eax
pushl %eax
call _stricmp
addl $8,%esp
movl %eax,%eax; выключенная оптимизация в действии:)
; А ведь недалеки времена, когда компиляторы только такое и умели генерировать.
testl %eax,%еах
jne L14
leal -264(%ebp),%еах
pushl %eax
pushl $LC2
movl 8(%ebp),%eax
pushl %eax
call _fprintf
addl $12,%esp
; Обратите внимание, что компилятор не стал генерировать второй эпилог
;функции на втором операторе return.
movl $200,%eax
jmp L13
; Выравнивание потенциальных точек перехода на границу слова полезно:
; процессор не будет тратить дополнительный цикл шины на чтение
; невыровненной команды. Для выравнивания используется команда NOP;
; (код операции 0x90).
align 2.0x90 L14:
leal -8(%ebp),%еах
Pushl %eax
Pushl $LC3
movl 8(%ebp),%eax pushl %eax
call _fprintf
addl?12,%esp
movl $500,%eax
jmp L13
.align 2.0x90 L13:
; Команда leave совершает действия, обратные прологу функции:
; Она эквивалентна командам: move %ebp, %esp; pop %ebp.
; Размер кадра явным образом не указывается, поэтому ограничений;
на этот размер в данном случае нет.
leave
ret
Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.