Написал на паскале hello world и решил посмотреть её ассемблерный вариант. Ограничиваясь набором инструментов, я получил такой вот код с At&T синтаксисом Код (Text): .file "hello.pas" .section .text .section .text .balign 16 .balign 16 # [hello.pas] # [4] begin .globl PASCALMAIN .type PASCALMAIN,@function PASCALMAIN: .globl main .type main,@function main: # Temps allocated between ebp-4 and ebp+0 pushl %ebp movl %esp,%ebp subl $4,%esp movl %ebx,-4(%ebp) call FPC_INITIALIZEUNITS # [5] writeln(msg); call fpc_get_output // получаем что-то movl %eax,%ebx // из eax это что-то пересылаем в ebx movl $_$PROGRAM$_L7,%ecx // это наше сообщение "hello" отправляется в ecx movl %ebx,%edx // ЭТО ДЛЯ ЧЕГО? movl $0,%eax // А xor eax, eax не катит? call fpc_write_text_shortstr // тааак... в eax у нас ноль, в ecx сообщение, что же передается функции? call FPC_IOCHECK movl %ebx,%eax call fpc_writeln_end call FPC_IOCHECK # [6] end. call FPC_DO_EXIT movl -4(%ebp),%ebx leave ret .section .data .balign 4 .globl _$PROGRAM$_L7 _$PROGRAM$_L7: .ascii "\005hello\000" .section .data .section .data .section .bss Скажите, откуда берутся вызовы к таким ф-циям как FPC_что-то? В какой это библиотеке? Что за странности в процедуре main?
1) FPC_INITIALIZEUNITS выполняется секция initialization 2) fpc_get_output получаем хэндл устройства для вывода 3) fpc_write_text_shortstr параметры передаётся через регистры ЗЫ. Компилятор FPC это конечно жесть...
я тоже натыкался на подобные вещи. Кажется это связано с фичами компилятора, типа выравнивание и все такое. Когда то не много юзал ARM7, просматривал дизасм сишного текста в отладчике, на инструкции "int i=-1" увидел что то типа Код (Text): mov dword ptr xxx,0xFF0000FF or dowrd ptr xxx,0x00FFFF00 много думал, пришел к выводу, что либо особенности работы с памятью, о которых не ведаю, либо маркетинговая фишка компилятора (среда разработки бесплатная, тестовая)
device в eax - хэндлер выходного потока этот хэндлер сохраняется в ebx в edx хэндлер выходного потока Может и не катит, от компилятора зависит, в частности А функции передаются через регистры три параметра: eax - 0 (если честно, не знаю, что это за параметр, нужно смотреть прототип функции, либо исходники), edx - хэндлер выходного потока, ecx - указатель на выводимую в поток строку. ЗЫ Если бы ты посмотрел на файл, созданный Дельфи, увидел бы очень похожие вещи. Barbos Странные какие-то инструкции... Вот для процессоров архитектуры RISC константы могут формироваться "необычным" образом (все-таки длина инструкции ограничена). А здесь - х.з.
FPC по-настоящему оптимизировать не умеет. Так что "movl $0,%eax" вместо "xorl %eax,%eax" - это следствие тупого компилятора. Код с разбивкой на функциональные блоки с комментариями: Код (Text): # Temps allocated between ebp-4 and ebp+0 pushl %ebp movl %esp,%ebp subl $4,%esp Вход в функцию, создание стекового фрейма на 4 байта - это одна переменная [ebp-4]. Код (Text): movl %ebx,-4(%ebp) Сохранение в этой переменной значения регистра ebx. Сам регистр ebx будет использован для хранения неких данных. Код (Text): call FPC_INITIALIZEUNITS Вызов, вставляемый компилятором в функцию main. Тут дело в следующем: в паскале перед выполнением собственно main() должны вызваться инициализирующие функции других модулей (тех, у которых такие функции есть), в их число всегда входит неявный System. Вот и вызывается специальная функция FPC_INITIALIZEUNITS из библиотеки FPC (кстати, вся библиотека написана на самом FPC). В Си несколько похожие процессы организованы по-другому. Код (Text): # [5] writeln(msg); call fpc_get_output // получаем что-то movl %eax,%ebx // из eax это что-то пересылаем в ebx На псевдо-Си это присваивание "ebx = stdout;" Код (Text): movl $_$PROGRAM$_L7,%ecx // это наше сообщение "hello" отправляется в ecx movl %ebx,%edx // ЭТО ДЛЯ ЧЕГО? movl $0,%eax // А xor eax, eax не катит? call fpc_write_text_shortstr // тааак... в eax у нас ноль, в ecx сообщение, что же передается функции? call FPC_IOCHECK На псевдо-Си первые 4 строчки - это вызов функции "fpc_write_text_shortstr(0,ebx,$_$PROGRAM$_L7);" FPC (по дефолту; а библиотеки fpc именно так и компилятся) использует схему вызова fastcall - первые 3 параметра передаются в регистрах eax,edx,ecx, ну а если параметров больше, включается стек. Последний вызов - вставлен компилятором и отвечает за реализацию директивы {$I+} - I/O checking - если произошла ошибка, будет ругательство со стороны библиотеки, и за это как раз и отвечает FPC_IOCHECK. Код (Text): movl %ebx,%eax call fpc_writeln_end call FPC_IOCHECK Соответственно, "fpc_writeln_end(ebx);" Код (Text): # [6] end. call FPC_DO_EXIT Опять же вставленный компилятором код - на сей раз корректно обрабатывающий выход из программы и вставляющийся в конце main(). Кстати, функция не возвращает управления, но компилятор этого не замечает и Код (Text): movl -4(%ebp),%ebx leave ret Восстанавливаем ebx, отключаем кадр стека, выходим из функции. В RTL от FreePascal'я. Библиотека поставляется вместе с компилятором.
Ответ счерпывающий. Многое проясняется. Вообще, интересно смотреть, что выводят компилеры разные. Вот, та же программа hello, собраная ГНАТом. Рабочих там от силы 10 строк, а дальше - не понятно что идет. Код (Text): .long 0x0 .byte 0x1 .string "zP" .uleb128 0x1 .sleb128 -4 .byte 0x8 .uleb128 0x5 .byte 0x0 .long __gnat_eh_personality .byte 0xc .uleb128 0x4 .uleb128 0x4 .byte 0x88 .uleb128 0x1 .align 4 .LECIE1: .LSFDE1: .long .LEFDE1-.LASFDE1 .LASFDE1: .long .LASFDE1-.Lframe1 .long .LFB3 .long .LFE3-.LFB3 .uleb128 0x0 .byte 0x4 .long .LCFI0-.LFB3 .byte 0xc .uleb128 0x1 .uleb128 0x0 .byte 0x9 .uleb128 0x4 .uleb128 0x1 .byte 0x4 .long .LCFI1-.LCFI0 .byte 0xc .uleb128 0x4 .uleb128 0x4 .byte 0x4 .long .LCFI2-.LCFI1 .byte 0xe .uleb128 0x8 .byte 0x85 .uleb128 0x2 .byte 0x4 .long .LCFI3-.LCFI2 .byte 0xd .uleb128 0x5 .byte 0x4 .long .LCFI4-.LCFI3 .byte 0x84 .uleb128 0x3 .align 4 .LEFDE1: .ident "GCC: (GNU) 4.1.1 20061011 (Red Hat 4.1.1-30)" Что это за фигня? Вижу, что данные, но для чего они нужны - не пойму. В LASFDE1 вычисляется размер каких-то фреймов. Что внутри этих фреймов, я показывать не буду, ибо цензура не пропустит.