ИАТЭ НИЯУ МИФИ Кафедра КССТ Лабораторная работа №1 "Раздельная трансляция" Выполнил: студент гр.ВТ-с-09 Панюков А.М. Проверила: Тищенко В. И. Обнинск 2012 Цель работы. Произвести раздельную трансляцию, изучить способы определения сегментов (посредством упрощенных директив и используя директиву SEGMENT), изучить директивы PUBLIC и EXTERN, изучить структуру объектного модуля (.obj - файла) и таблицы перекрестных ссылок. Выполнение работы. Раздельная трансляция программы на ассемблере Для раздельной трансляции использую программу, которая считает количество цифр в строке. Суть раздельной трансляции состоит в разделении программы на два модуля (вызывающий и вызываемый модули). В вызываемом модуле, с помощью директивы PUBLIC, указывают на то, что процедура, описанная в данном модуле, будет вызываться из другого модуля. В вызывающем модуле, с помощью директивы EXTRN, необходимо указать, что вызываемая в нем процедура описывается в другом модуле. Трансляция и компоновка осуществляется следующим образом: tasm A /l /c tasm B /l /c tlink A+B, main, /s где main - имя общего скомпонованного модуля. /l - создается файл листинга. /c - помещается в файл листинга таблица перекрестных ссылок. /s - помещается в файл карты памяти (.map) детализированную карту сегментов программу. Для передачи параметров в процедуру и определения меток была использована директива ассемблера EXTRN, которая позволяет использовать метки и переменные, объявленные в другом файле. Для того чтобы процедура была доступна в другой программе, используется директива PUBLIC. Файлы листинга Файлы листинга содержат следующее: Первая строка содержит версию TASM, время и дату создания листинга. Вторая строка - имя файла листинга. Далее идет группа строк в виде последовательности: <глубина вложенности> - уровень вложенности включаемых файлов или макрокоманд (может отсутствовать) <номер строки> - номер строки в файле листинга <смещение> - смещение в байтах текущей команды относительно начала сегмента кода <машинный код> - машинное представление команды ассемблера <исходный код> - строка кода из исходного файла. Далее идет таблица символов. В нее входят символические имена всех переменных, меток программы. Если имена начинаются с символов ?? или @, то это встроенные имена TASM. В данном листинге содержится таблица перекрестных ссылок. В этой части листинга указываются номера строк, в которых описаны символические имена и номера строк, в которых они используются. В поле перекрестных ссылок указываются, для каждого идентификатора (метки, группы или сегмента), номера всех тех строк в программе, где имеется ссылка на данный идентификатор. Перед строками, на которых был определен идентификатор, указывается символ #. Далее следует информация о группах и сегментах, значение модификатора, выравнивание, атрибут комбинирования, класс. Способы определения сегментов в программе на ассемблере. (*.map файл) В *.map файле содержится следующая информация о сегментах: начало и конец сегментов, их длина, их имя, класс и точка входа в программу; в расширенной карте сегментов указывается расположение каждого сегмента отдельно от транслированного модуля. 1.Сегменты определены через директивы: .data , .code .DATA (.data) - определяет начало инициализированного сегмента данных с именем _DATA и при наличии предыдущего сегмента завершает его. Этой директиве должна предшествовать директива .MODEL. Сегмент, определенный с атрибутом .DATA, должен содержать только инициализированные данные, то есть имеющие начальные значения. .CODE (.code) [имя] - определяет сегмент программного кода и заканчивает предыдущий сегмент, если таковой имеется. Необязательный параметр имя замещает имя _TEXT, заданное по умолчанию. Если имя не определено, ассемблер создает сегмент с именем _TEXT для моделей памяти tiny, small, compact и flat или сегмент с именем имя_модуля_TEXT для моделей памяти medium, large и huge. Этой директиве должна предшествовать директива .MODEL, указывающая модель памяти, используемую программой. .MODEL (.model) модель_памяти [,соглашение_о_вызовах] [,тип_ОС] [,параметр_стека] - определяет модель памяти, используемую программой. Директива должна находиться перед любой из директив объявления сегментов. Она связывает определенным образом различные сегменты программы, определяемые ее параметрами tiny, small, compact, medium, large, huge или flat. Параметр модель_памяти является обязательным. 1) Листинг вызываемого модуля (anton111.lst). 10000 model small 20000 .stack 100h 30000 .data 40000 .code 5 extrn start:far 60000 begin procfar 70000 0E E8 0000e call start 8 90004 B8 4C00 mov ax,4c00h 100007 CD 21 int 21h 11 120009 begin endp 13 end begin Symbol Table Symbol NameType Value Cref(defined at #) ??DATEText "03/19/12" ??FILENAMEText "anton111" ??TIMEText "19:03:45" ??VERSIONNumber 030A @32BITText 0 #1 @CODEText _TEXT #1 #1 #4 @CODESIZEText 0 #1 @CPUText 0101H @CURSEGText _TEXT #3 #4 @DATAText DGROUP #1 @DATASIZEText 0 #1 @FILENAMEText ANTON111 @INTERFACEText 00H #1 @MODELText 2 #1 @STACKText DGROUP #1 @WORDSIZEText 2 #3 #4 BEGINFar _TEXT:0000 #6 13 STARTFar _TEXT:---- Extern #5 7 Groups & SegmentsBit Size AlignCombineClass Cref(defined at #) DGROUPGroup #1 1 STACK16 0100 ParaStackSTACK #2 _DATA16 0000 WordPublicDATA #1 #3 _TEXT16 0009 WordPublicCODE #1 1 #4 4 2) Листинг вызывающего модуля (anton222.lst) 10000 model small 2 public start 30000 .stack 100h 40000 .data 50000 00 kolvo db 00h 60001 30 30 24 outp db '00$' 7 80004 .code 90000 start proc far 100000 star: 110000 B8 0000s mov ax,@data 120003 8E D8 mov ds,ax 13 140005 26: 8A 0E0080 mov cl,es:[80h] 15000A 80 F9 02 cmp cl,2h 16000D 7C 2F jl noinput 17000F B5 00 mov ch,00h 180011 FE C9 dec cl 19 20 210013 BE 0000 mov si,00h 22 230016 next: 240016 26: 8A A40082 mov ah,es:[si+82h] 25001B 80 FC 39 cmp ah,'9' 26001E 7F 04 jg notinc 270020 FE 06 0000r inc kolvo 280024 notinc: 290024 46 inc si 300025 3B F1 cmp si,cx 310027 75 ED jne next 32 330029 A0 0000r mov al,kolvo 34002C B4 00 mov ah,00h 35002E B2 0A mov dl,10 360030 F6 FA idiv dl 370032 80 C4 30 add ah,'0' 380035 04 30 add al,'0' 390037 A2 0001r mov outp,al 40003A 88 26 0002r mov outp[1],ah 41 42003E noinput: 43 44003E B4 09 mov ah,09h 450040 BA 0001r mov dx,offset outp 460043 CD 21 int 21h 47 48 490045 start endp 50 end Symbol Table Symbol NameType Value Cref(defined at #) ??DATEText "03/19/12" ??FILENAMEText "anton222" ??TIMEText "19:03:51" ??VERSIONNumber 030A @32BITText 0 #1 @CODEText _TEXT #1 #1 #8 @CODESIZEText 0 #1 @CPUText 0101H @CURSEGText _TEXT #4 #8 @DATAText DGROUP #1 11 @DATASIZEText 0 #1 @FILENAMEText ANTON222 @INTERFACEText 00H #1 @MODELText 2 #1 @STACKText DGROUP #1 @WORDSIZEText 2 #4 #8 KOLVOByte DGROUP:0000 #5 27 33 NEXTNear _TEXT:0016 #2331 NOINPUTNear _TEXT:003E 16 #42 NOTINCNear _TEXT:0024 26 #28 OUTPByte DGROUP:0001 #6 39 40 45 STARNear _TEXT:0000 #10 STARTFar _TEXT:0000 2 #9 Groups & SegmentsBit Size AlignCombineClass Cref(defined at #) DGROUPGroup #1 1 11 STACK16 0100 ParaStackSTACK #3 _DATA16 0004 WordPublicDATA #1 #4 _TEXT16 0045 WordPublicCODE #1 1 #8 8 Карта памяти: Start Stop Length Name Class 00000H 0004EH 0004FH _TEXT CODE 00050H 00053H 00004H _DATA DATA 00060H 0025FH 00200H STACK STACK Detailed map of segments 0000:0000 0009 C=CODE S=_TEXT G=(none) M=ANTON111.ASM ACBP=48 0000:000A 0045 C=CODE S=_TEXT G=(none) M=ANTON222.ASM ACBP=48 0005:0000 0000 C=DATA S=_DATA G=DGROUP M=ANTON111.ASM ACBP=48 0005:0000 0004 C=DATA S=_DATA G=DGROUP M=ANTON222.ASM ACBP=48 0005:0010 0100 C=STACK S=STACK G=DGROUP M=ANTON111.ASM ACBP=74 0005:0110 0100 C=STACK S=STACK G=DGROUP M=ANTON222.ASM ACBP=74 Address Publics by Name 0000:000A START Address Publics by Value 0000:000A START Program entry point at 0000:0000 Если в команде TLINK поменять местами модули т.е. tlink A2+A1,main,/s ,то карта памяти изменилась, и программа успешно работала. Detailed map of segments 0000:0000 0045 C=CODE S=_TEXT G=(none) M=ANTON222.ASM ACBP=48 0000:0046 0009 C=CODE S=_TEXT G=(none) M=ANTON111.ASM ACBP=48 0005:0000 0004 C=DATA S=_DATA G=DGROUP M=ANTON222.ASM ACBP=48 0005:0004 0000 C=DATA S=_DATA G=DGROUP M=ANTON111.ASM ACBP=48 0005:0010 0100 C=STACK S=STACK G=DGROUP M=ANTON222.ASM ACBP=74 0005:0110 0100 C=STACK S=STACK G=DGROUP M=ANTON111.ASM ACBP=74 Address Publics by Name 0000:0000 START Address Publics by Value 0000:0000 START Program entry point at 0000:0046 Меняем расстояние с FAR на NEAR: Процедуры NEAR вызываются с помощью вызова ближнего типа исодержат ближний возврат управления. Вы должны вызывать их тольков том же сегменте, в котором они определены. Вызов ближнего типазаносит адрес возврата в стек и устанавливает указатель инструк-тор (IP) в значение смешения процедуры. Поскольку сегмент кода(CS) не изменяется, процедура должна находиться в том же сегмен-возврат ближнего типа, он извлекает из стека адрес возврата иснова устанавливает в него IP. Сегмент кода не изменяется. Процедура FAR вызывается с помощью вызова дальнего типа исодержит возврат дальнего типа. Процедуры FAR вы можете вызыватьвне сегмента, в котором они определяются. Вызов FAR заносит встек адрес в виде сегмента и смещения, а затем устанавливаетCS:IP в адрес процедуры. Когда процессор обнаруживает возврат дальнего типа, он извлекает из стека сегмент и смещение адреса возврата и устанавливает в него CS:IP. Расстояние (NEAR или FAR), используемое в процедуре по умол-чанию, определяется текущей выбранной моделью. Для моделей TINY,SMALL и COMPACT по умолчанию процедура будет ближней (NEAR). Длявсех других моделей по умолчанию выбирается расстояние FAR. Есливы не используете упрощенные директивы определения сегментов, топо умолчанию процедура всегда будет ближней (NEAR). Листинг модуля Anton111 потерпел некоторые изменения ; 5 extrn start:near 60000 begin procfar 70000 E8 0000e call start 8 90003 B8 4C00 mov ax,4c00h 100006 CD 21 int 21h 11 120008 begin endp 13 end begin И в таблице символов STARTNear _TEXT:---- Extern #5 7 Листинг модуля Anton222 незначительно изменился: 90000 start proc near И в таблице символов STARTNear _TEXT:0000 2 #9 Карта памяти скомпонованного модуля тоже изменилась: Start Stop Length Name Class 00000H 0004CH 0004DH _TEXT CODE 00050H 00053H 00004H _DATA DATA 00060H 0025FH 00200H STACK STACK Detailed map of segments 0000:0000 0008 C=CODE S=_TEXT G=(none) M=NEAR1.ASM ACBP=48 0000:0008 0045 C=CODE S=_TEXT G=(none) M=NEAR2.ASM ACBP=48 0005:0000 0000 C=DATA S=_DATA G=DGROUP M=NEAR1.ASM ACBP=48 0005:0000 0004 C=DATA S=_DATA G=DGROUP M=NEAR2.ASM ACBP=48 0005:0010 0100 C=STACK S=STACK G=DGROUP M=NEAR1.ASM ACBP=74 0005:0110 0100 C=STACK S=STACK G=DGROUP M=NEAR2.ASM ACBP=74 Address Publics by Name 0000:0008 START Address Publics by Value 0000:0008 START Program entry point at 0000:0000 Переместим ссылку на процедуру extrn start:near выше: Листинг Anton111: 1 extrn start:far 20000 model small 30000 .stack 100h 40000 .data 50000 .code 6 70000 begin procfar 80000 9A 00000000se call start 9 100005 B8 4C00 mov ax,4c00h 110008 CD 21 int 21h 12 13000A begin endp 14 end begin В таблице символов изменилась одна строчка: STARTFar ----:---- Extern #1 8 Так же все числа соответствующие номерам строк увеличены на 1. Еще изменилась последняя строчка полем size : _TEXT16 0009 WordPublicCODE #1 1 #4 4 Листинг Anton222 не изменился . В карте памяти изменилась одна строчка : Detailed map of segments 0000:0000 000A C=CODE S=_TEXT G=(none) M=EXUP1.ASM ACBP=48 Сегменты определены через директиву segment Директива SEGMENT определяет логический сегмент и может быть описана следующим образом: имя SEGMENT список атрибутов . . . имя ENDS При использовании директивы SEGMENT потребуется указать компилятору на то, что все сегментные регистры устанавливаются в соответствии с моделью памяти. Это можно сделать при помощи директивы ASSUME: ASSUME CS:Code, DS:data, SS:stack, ES:ERROR, FS:ERROR, GS:ERROR Регистры FS и GS программами не используются, поэтому для них указывается атрибут ERROR. 1) Листинг вызываемого модуля (anton111.lst). 10000 stk segment stack 20000 0100*(00) db256 dup(0) 30100 stk ends 40000 data segment 50000 data ends 60000 code segment 7 extrn start:far 80000 begin procfar 9 assume cs:code,ds:data,ss:stk 100000 0E E8 0000e call start 11 120004 B8 4C00 mov ax,4c00h 130007 CD 21 int 21h 140009 begin endp 150009 code ends 16 end begin Symbol NameType Value Cref(defined at #) ??DATEText "03/19/12" ??FILENAMEText "anton111" ??TIMEText "19:47:31" ??VERSIONNumber 030A @CPUText 0101H @CURSEGText CODE #1 #4 #6 @FILENAMEText ANTON111 @WORDSIZEText 2 #1 #4 #6 BEGINFar CODE:0000 #8 16 STARTFar CODE:---- Extern #7 10 Groups & SegmentsBit Size AlignCombineClass Cref(defined at #) CODE16 0009 Paranone #6 9 DATA16 0000 Paranone #4 9 STK16 0100 ParaStack #1 9 2) Листинг вызывающего модуля (anton222.lst) 1 public start 20000 stk segment stack 30000 0100*(00) db256 dup(0) 40100 stk ends 50000 data segment 60000 00 kolvo db 00h 70001 30 30 24 outp db '00$' 80004 data ends 90000 code segment 100000 start proc far 11 assume cs:code,ds:data,ss:stk 120000 star: ................................................................................. 46003E B4 09 mov ah,09h 470040 BA 0001r mov dx,offset outp 480043 CD 21 int 21h 490045 start endp 500045 code ends 51 end Symbol NameType Value Cref(defined at #) ??DATEText "03/19/12" ??FILENAMEText "anton222" ??TIMEText "19:47:38" ??VERSIONNumber 030A @CPUText 0101H @CURSEGText CODE #2 #5 #9 @FILENAMEText ANTON222 @WORDSIZEText 2 #2 #5 #9 KOLVOByte DATA:0000 #6 29 35 NEXTNear CODE:0016 #2533 NOINPUTNear CODE:003E 18 #44 NOTINCNear CODE:0024 28 #30 OUTPByte DATA:0001 #7 41 42 47 STARNear CODE:0000 #12 STARTFar CODE:0000 1 #10 Groups & SegmentsBit Size AlignCombineClass Cref(defined at #) CODE16 0045 Paranone #9 11 DATA16 0004 Paranone #5 11 13 STK16 0100 ParaStack #2 11 Карта памяти: Start Stop Length Name Class 00000H 001FFH 00200H STK 00200H 00200H 00000H DATA 00200H 00203H 00004H DATA 00210H 00218H 00009H CODE 00220H 00264H 00045H CODE Detailed map of segments 0000:0000 0100 C= S=STK G=(none) M=ANTON111.ASM ACBP=74 0000:0100 0100 C= S=STK G=(none) M=ANTON222.ASM ACBP=74 0020:0000 0000 C= S=DATA G=(none) M=ANTON111.ASM ACBP=60 0020:0000 0004 C= S=DATA G=(none) M=ANTON222.ASM ACBP=60 0021:0000 0009 C= S=CODE G=(none) M=ANTON111.ASM ACBP=60 0022:0000 0045 C= S=CODE G=(none) M=ANTON222.ASM ACBP=60 Address Publics by Name 0022:0000 START Address Publics by Value 0022:0000 START Program entry point at 0021:0000 Если в команде TLINK поменять местами модули т.е. tlink A2+A1,main,/s ,то Start Stop Length Name Class 00000H 001FFH 00200H STK 00200H 00203H 00004H DATA 00210H 00210H 00000H DATA 00210H 00254H 00045H CODE 00260H 00268H 00009H CODE Detailed map of segments 0000:0000 0100 C= S=STK G=(none) M=ANTON222.ASM ACBP=74 0000:0100 0100 C= S=STK G=(none) M=ANTON111.ASM ACBP=74 0020:0000 0004 C= S=DATA G=(none) M=ANTON222.ASM ACBP=60 0021:0000 0000 C= S=DATA G=(none) M=ANTON111.ASM ACBP=60 0021:0000 0045 C= S=CODE G=(none) M=ANTON222.ASM ACBP=60 0026:0000 0009 C= S=CODE G=(none) M=ANTON111.ASM ACBP=60 Address Publics by Name 0021:0000 START Address Publics by Value 0021:0000 START Error: Fixup overflow at CODE:0002, target = START in module ANTON111.ASM Program entry point at 0026:0000 Структура объектного модуля (Anton111.obj файла). Все объектные записи имеют следующий вид. <------Record Length in Bytes-----> 1 2 <variable> 1 Record Record Record Checksum or 0 Type Length Contents Поле Record Type - 1-байтовое поле, содержащее 16-ричное число, которое идентифицирует тип объектной записи. Поле Record Length - 2-байтовое поле, которое дает длину остатка от объектной записи в байтах (исключая байты в полях Record Type и Record Length). Длина записи хранится с байтом младшего разряда. Полная запись занимает 3 байта плюс число байт в поле Record Length. Поле Record Contents изменяется по размеру и формату в зависимости от типа записи. Поле Checksum - 1-байтовое поле, которое содержит отрицательную сумму (модуль 256) всех других байт в записи. Другими словами, байт контрольной суммы рассчитан так, чтобы младший разряд байта суммы всех байтов в записи, включая байт контрольной суммы, равнялся 0. Переполнение игнорируется. Некоторые компиляторы пишут скорее 0 байт, чем вычисление контрольной суммы, поэтому любая форма должна быть допустима для программ. Разберем в данном модуле несколько объектных записей: 8Ch - Определение внешних имен (EXTDEF) 8Ah-конец объектного модуля 96h - Имена сегментов/групп (LNAMES) 98h - Информация об определенном сегменте (SEGDEF) 90h - Запись определения открытых имён (Public Names Definition Record)(В модуле Anton222.obj) 8Ch - внешние имена Запись содержит список символических внешних ссылок, т.е. ссылок на имена, определённых в других объектных модулях. Компоновщик делает вывод, что ссылки являются внешними, сравнивания имена, объявленные в записях типа 8Ch (EXTDEF), с именами, объявленными в записях типа 90h (PUBDEF). Формат записи: 1 2 1 <Длина Строки> 1 или 2 1 8Ch Длина Длина Строка Индекс Контрольная Сумма Записи Строки Внешнего Имени Типа Длина Строки - это однобайтовое поле, содержащее длину поля имени, следующего за ним. Компоновщик ограничивает длину имени значением между 1 и 7Fh. Поле Индекс Типа закодировано как индексное поле и содержит конфиденциальную информацию о типе представления кода. В то же время, компоновщик не выполняет проверку какого-либо типа Объявление внешнего имени:8c 08 00 05 53 54 41 52 54 00 d9 08 00 -Длина записи 8 байт 05 - длина строки 53 54 41 52 54 - строка START 00 - индекс типа d9 - контрольная сумма 96h - имена сегментов/групп Эта запись является списком имён, на которые могут ссылаться последующие записи SEGDEF и GRPDEF. Положение имён упорядочено и на них могут быть установлены ссылки по индексу из последующих записей. Может быть более одной записи LNAMES. Имена могут означать сегмент, класс, группу, оверлей и селекторные имена. Формат записи: 1 2 1 <--Длина Строки--> 1 96h Длина Длина Строка Имени Контрольная Сумма Записи Строки <-----------повторяется-----------> Каждое имя представляется в формате <количество символов, символы>, допускается пустое имя. Символы представляются в формате ASCII. 96 02 00 00 68 02 00 -длина записи 00 длина строки 68 - контрольная сумма 98h - информация об определённом сегменте Описание. Запись SEGDEF описывает логические сегменты в объектном модуле. Определяет имя сегмента, его длину, выравнивание и способ, которым этот сегмент может быть объединён с другими логическими сегментами во время компоновки или загрузки. Записи объектного файла, которые следуют за записью SEGDEF, могут ссылаться на неё с тем, чтобы идентифицировать определённый сегмент. Записи SEGDEF упорядочены и на них могут быть установлены ссылки по сегментным индексам из последующих записей. Формат записи: 1 2 <переменная> 2 или 4 1 или 2 1 или 2 1 или 2 1 98 Длина Свойства Длина Индекс Индекс Индекс Контрольная сумма Записи Сегмента Сегмента Имени Имени Имени Сегмента Класса Оверлея Поле Свойства Сегмента <-3 bits-> <-3 bits-> <-1 bit-> <-1 bit-> <-2 bytes--> <--1 byte--> A C B P Структурный Смещение Номер <условно> <условно> Aвыравнивание 0 постоянный сегмент 1 перемещаемый, BYTE 2 перемещаемый, WORD 3 перемещаемый, PARA 4 перемещаемый, PAGE 5 перемещаемый, выравнивание по двойному слову (4 байта) 6 OMF, страничное выравнивание (4 Кбайт) 7 не определено Собъединение 0 нет объединения 1 используется IBM, не поддерживается Microsoft 2 Public 3 смотрите 1 4 определено Microsoft, аналогично Public 5 Stack 6 Common 7 определено Microsoft, аналогично Public Bиспользуется как старший бит поля Длина Сегмента; если этот бит установлен, значение длины сегмента должно быть 0. Pесли 0, то размер сегмента не больше 64 Кбайт (если сегмент данных), и по умолчанию установлена 16-битовая адресация и опренды (если сегмент кода). Длина слова сегмента use16. Поле длина Сегмента Поле Длина Сегмента - это 2- или 4-байтовая величина и определяет количество байтов в этом программном сегменте. Поля Индекс Имени Сегмента, Индекс Имени Класса и Индекс Имени Оверлея Эти три поля ссылаются на имена, которые объявлены в предыдущих записях LNAMES. 98 07 00 48 09 00 02 03 01 0a 07 00 -длина записи 48 - ACBP: 01001000 A 010 - WORD C 010 - PUBLIC B 0 - длина сегмента не равна 0; P 0 - 16-битовая адресация 09 00 - длина сегмента 9 байт 02 - индекс имени сегмента 03 - индекс имени класса 01 - индекс имени оверлея 0a - контрольная сумма 8Ah - конец объектного модуля Так же указывается, содержит ли объектный модуль главную подпрограмму в программе и может опционально содержать ссылку на точку входа в программу. 8A 07 00 С1 00- Начальный адрес(Start address) Вывод. В данной лабораторной работе я изучил структуру листинга, *.map и *.obj файлы. Листинг и *.map файл позволяет получить подробную информацию о сегментах, понять, как распределяются адреса под сегменты в зависимости от способа их определения. . Объектный модуль несет в себе много информации, полезной программисту (информация об инициализации регистров, информация об определенном сегменте, определение внешних имен, содержимое сегмента и т.д.).
1/--страниц