2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




На страницу Пред.  1, 2, 3, 4  След.
 
 Re: Hello world
Сообщение09.06.2013, 20:10 
Компилятор не знает, что вы собираетесь получить COM. Он просто готовит объектный файл. Объектный файл содержит код, данные и различную служебную информацию (в частности, что в какие сегменты пихать). А вот уже линкер из объектного файла собирает исполняемый файл. Если вы укажите линкеру делать COM, то он тупо проигнорирует всю информацию про сегменты.

 
 
 
 Re: Hello world
Сообщение09.06.2013, 23:46 
Аватара пользователя
Теперь все понятно, спасибо за разъяснение!

 
 
 
 Re: Hello world
Сообщение10.06.2013, 17:32 
Аватара пользователя
Опять ступор. :x Написал код
Используется синтаксис ASM
.model small
.data
msg db 'message $'
.code
org 100h
start:
mov ah,09h
mov dx, offset msg
int 21h
ret
end start
Скомпилил .COM файл. Вылетает почти как если бы в dx был 0 (если запихать в dx 0, то в начале выводится еще 2 символа). Если написать
Используется синтаксис ASM
.model small
.code
org 100h
start:
mov ah,09h
mov dx, offset msg
int 21h
ret
msg db 'message $'
end start
то все нормально.
Почему результат разный?

 
 
 
 Re: Hello world
Сообщение10.06.2013, 18:23 
Замените модель на tiny, либо линкуйте в exe. В последнем случае нужно ещё вручную инициализировать сегмент данных:
Код:
mov ax,@data
mov ds,ax

(Почему так произошло)

В модели small предполагается, что данные в отдельном сегменте. Поэтому компилятор, видимо, в объектнике указал, что msg лежит в сегменте DATA по адресу 0. Линкер, собирая COM, склеил CODE и DATA, и установил адрес msg на смещение DATA (как в файле). То есть "offset msg" заменился на адрес, на 100h меньший нужного (помним, что система при загрузке COM первые 100h сегмента кода заполняет служебной информацией и только потом идёт программа). Можете ради эксперимента заменить в первом варианте "offset msg" на "offset msg+100h". Но в реальном коде так не надо делать.

 
 
 
 Re: Hello world
Сообщение10.06.2013, 18:42 
Насколько я помню, компоновщик располагает сегменты в исполняемом файле в порядке их появления в программе. А COM-файл грузится следующим образом. Сначала создается префикс программного сегмента (PSP), который занимает 256 (= 100h) байт. Сразу за PSP копируется информация из файла. Все сегментные регистры устанавливаются на начало PSP, SP устанавливается в FFFEh, а IP - в 100h. А у вас, возможно, по адресу 100h находится строка msg.

PS. Кстати, первые два байта PSP - это CD 20 - код команды int 20h, а в вершине стека записывается 0. Так что COM-программу можно завершать командой ret, что экономит 1 байт.

 
 
 
 Re: Hello world
Сообщение11.06.2013, 15:29 
Аватара пользователя
lena7 в сообщении #735065 писал(а):
Линкер, собирая COM, склеил CODE и DATA, и установил адрес msg на смещение DATA (как в файле).

У меня какая-то путаница. Гугляж говорит, что ассемблер преобразует исходный код в машинный и составляет таблицу перекрестных ссылок и таблицу сегментов. Сказано, что составление таблицы перекрестных ссылок это значит пометить участки куда, куда надо будет записать адреса внешних ссылок , глобальных функций и глобальных переменных. Составление таблицы сегментов- это значит пометить сегмент кода и сегмент данных. Т.е. этот момент
lena7 в сообщении #735065 писал(а):
Поэтому компилятор, видимо, в объектнике указал, что msg лежит в сегменте DATA по адресу 0.

не понятен, ведь исходя из определния, что я привел выше не видно, чтобы были где-то записаны адреса. Может я не верно понял что значит "пометить участок кода".
При попытки посмотреть объектник ничего не получается, там каша какая-то.
lena7 в сообщении #735065 писал(а):
Код:
Код:
mov ax,@data
mov ds,ax


Не понял, зачем сначала пересылка в ax, почему сразу не в ds?

Я пытался переслать данные из ip в dx, но компилятор выдает ошибку "Undefined symbol: IP". Регистр IP вообще нельзя трогать?

 
 
 
 Re: Hello world
Сообщение11.06.2013, 15:58 
Зачем вам знать, как работает tasm, tlink в формат используемых там объектных файлов (с точки зрения изучения ассемблера)?

(Оффтоп)

Грубо говоря, компилятор (ассемблер в вашем случае) берёт исходный код программы и генерирует объектный файл. Объектный файл содержит информацию о сегментах, символах (переменные, функции), машинный код, сгенерированный компилятором (но не все адреса там верно установлены), данные, отладочную информацию и др. Когда в исходном коде есть, скажем, "offset" или ссылка на какие-либо символы, то ассемблер не всегда знает, какими адресами их заменять. Конкретные адреса в конечном исполняемом файле (точнее, в памяти, куда система его загрузит) будут известны лишь линкеру. Поэтому компилятор лишь записывает в объектник некоторую информацию, помогающую линкеру правильно проставить потом адреса. Конкретные детали зависят от реализации компилятора, линкера и формата используемых объектных файлов.

Я уже указала, что надо сделать, чтобы исправить ошибку. Причина ошибки в том, что компилятор хотел сделать DATA отдельным сегментом (что ему диктовала модель small), а линкер -- склеил его с CODE (ибо он делал COM).

(Оффтоп)

Замечу, что tlink не настолько глуп, чтобы даже в этом случае поместить DATA перед CODE в выходном COM-файле. Так что строка msg у вас попала не на адрес 100h, а дальше -- 100h+(размер кода). Однако "offset msg" заменилось на просто (размер кода).

xmaister в сообщении #735417 писал(а):
Не понял, зачем сначала пересылка в ax, почему сразу не в ds?

Не выйдет. Нет инструкции процессора, которая бы записывала в ds сразу непосредственное значение. Но зато есть инструкция, записывающая в ax непосредственное значение и инструкция, копирующая ax в ds.

xmaister в сообщении #735417 писал(а):
Регистр IP вообще нельзя трогать?

Опять же -- нет инструкций, обращающихся к ip напрямую. Однако вытащить ip можно, если вспомнить, что call кладёт в стек адрес следующей инструкции, прежде чем перейти по указанному адресу.

 
 
 
 Re: Hello world
Сообщение11.06.2013, 20:07 
xmaister в сообщении #735417 писал(а):
При попытки посмотреть объектник ничего не получается, там каша какая-то.

Смотреть нужно .LST, .MAP, не .OBJ. Для этого должна быть включена соответствующая опция компилятора.

 
 
 
 Re: Hello world
Сообщение12.06.2013, 00:32 
Аватара пользователя

(Оффтоп)

lena7 в сообщении #735425 писал(а):
Зачем вам знать, как работает tasm, tlink в формат используемых там объектных файлов (с точки зрения изучения ассемблера)?

А разве это не нужно знать чтобы понимать что происходит?

Tod Leben в сообщении #735515 писал(а):
Смотреть нужно .LST, .MAP, не .OBJ. Для этого должна быть включена соответствующая опция компилятора.

Вот .LST и теперь действительно видно, каким образом появляется строится объектный файл, в первом приближении
Код:
Turbo Assembler    Version 4.1       06/11/13 15:26:26       Page 1
hello.ASM



      1   0000              .model small
      2   0000              .data
      3   0000  48 65 6C 6C 6F 20   24   msg db 'Hello $'
      4   0007              .code
      5                 org 100h
      6   0100              start:
      7   0100  B4 09           mov ah,09h
      8   0102  BA 0000r           mov dx, offset msg
      9   0105  CD 21           int 21h
     10   0107  C3           ret
     11                 end start
Turbo Assembler    Version 4.1       06/11/13 15:26:26       Page 2
Symbol Table




Symbol Name           Type    Value

??DATE              Text    "06/11/13"
??FILENAME           Text    "hello     "
??TIME              Text    "15:26:26"
??VERSION           Number 040A
@32BIT              Text    0
@CODE              Text    _TEXT
@CODESIZE           Text    0
@CPU              Text    0101H
@CURSEG              Text    _TEXT
@DATA              Text    DGROUP
@DATASIZE           Text    0
@FILENAME           Text    HELLO
@INTERFACE           Text    000H
@MODEL              Text    2
@STACK              Text    DGROUP
@WORDSIZE           Text    2
MSG              Byte    DGROUP:0000
START              Near    _TEXT:0100

Groups & Segments        Bit Size Align  Combine Class

DGROUP              Group
  _DATA              16  0007 Word     Public  DATA
_TEXT              16  0108 Word     Public  CODE

и вот .lst если указать .model tiny
Код:
Turbo Assembler    Version 4.1       06/11/13 15:56:57       Page 1
hello.ASM



      1   0000              .model tiny
      2   0000              .data
      3   0000  48 65 6C 6C 6F 20   24   msg db 'Hello $'
      4   0007              .code
      5                 org 100h
      6   0100              start:
      7   0100  B4 09           mov ah,09h
      8   0102  BA 0000r           mov dx, offset msg
      9   0105  CD 21           int 21h
     10   0107  C3           ret
     11                 end start
Turbo Assembler    Version 4.1       06/11/13 15:56:57       Page 2
Symbol Table




Symbol Name           Type    Value

??DATE              Text    "06/11/13"
??FILENAME           Text    "hello     "
??TIME              Text    "15:56:57"
??VERSION           Number 040A
@32BIT              Text    0
@CODE              Text    DGROUP
@CODESIZE           Text    0
@CPU              Text    0101H
@CURSEG              Text    _TEXT
@DATA              Text    DGROUP
@DATASIZE           Text    0
@FILENAME           Text    HELLO
@INTERFACE           Text    000H
@MODEL              Text    1
@STACK              Text    DGROUP
@WORDSIZE           Text    2
MSG              Byte    DGROUP:0000
START              Near    DGROUP:0100

Groups & Segments        Bit Size Align  Combine Class

DGROUP              Group
  _DATA              16  0007 Word     Public  DATA
  _TEXT              16  0108 Word     Public  CODE

lena7 в сообщении #735425 писал(а):
Я уже указала, что надо сделать, чтобы исправить ошибку. Причина ошибки в том, что компилятор хотел сделать DATA отдельным сегментом (что ему диктовала модель small), а линкер -- склеил его с CODE (ибо он делал COM).

Да, это я уже проделывал и все нормально работает.
lena7 в сообщении #735425 писал(а):
Когда в исходном коде есть, скажем, "offset" или ссылка на какие-либо символы, то ассемблер не всегда знает, какими адресами их заменять.

Но тем не менее, ассемблер все равно проставил msg смещение 0:
Код:
MSG              Byte    DGROUP:0000
. Значит линкер это смещение скорректирует.
lena7 в сообщении #735425 писал(а):
Конкретные адреса в конечном исполняемом файле (точнее, в памяти, куда система его загрузит) будут известны лишь линкеру.

В данном случае, жто смещение msg, а значения DGROUP и _TEXT уже будет проставлено загрузчиком после запуска программы, верно?
lena7 в сообщении #735065 писал(а):
либо линкуйте в exe

линкую в .EXE результат почти тотже
Изображение
тут msg уехала на смещение 0108, хотя инструкция по смещению 0003 запишет в dx 0008A. :facepalm: Если не уберать org 100h то msg уехжает на смещение 0208

 
 
 
 Re: Hello world
Сообщение12.06.2013, 11:25 
xmaister в сообщении #735640 писал(а):
А разве это не нужно знать чтобы понимать что происходит?

С точки зрения изучения ассемблера и процессора -- нет. Для меня, компилятор + линкер -- это чёрный ящик, берущий исходный код и делающий исполняемый файл. Детали этого процесса зависят от реализации, причём сильно. Есть ассемблеры, которые даже не делят компиляцию и линковку, а сразу собирают исполняемый файл (именно сразу, а не скрывают этот процесс через временные объектные файлы). Например, fasm.

xmaister в сообщении #735640 писал(а):
Значит линкер это смещение скорректирует.

Да.

xmaister в сообщении #735640 писал(а):
а значения DGROUP и _TEXT уже будет проставлено загрузчиком после запуска программы, верно?

В исполняемом файле нет DGROUP и _TEXT. В COM-файле все адреса устанавливает линкер, система его тупо загружает... вы уже знаете как. EXE загружается сложнее. Если нужно, система откорректирует некоторые адреса в соответствии со специальной таблицей, хранящейся в EXE-файле (relocations).

xmaister в сообщении #735640 писал(а):
тут msg уехала на смещение 0108, хотя инструкция по смещению 0003 запишет в dx 0008A.

Вы опять забыли инициализировать ds?

Запомните:
COM: модель tiny, org 100h, линкова в COM.
EXE: модель small и выше, org 100h не надо, инициализировать используемые сегменты, кроме cs (его инициализирует система), линковка в EXE.

 
 
 
 Re: Hello world
Сообщение13.06.2013, 12:30 
Аватара пользователя
Так, попробую все собрать в "кучу", прочитайте пожалуйста, если не лень. Хотелось бы услышать ваши замечания. Модель памяти tiny подразумевает использование одного сегмента 64кб куда будет загружено код и данные. Если указать модель памяти tiny, то ассемблер зарезервирует первые 100h байт под PSP. Далее, если линковать .EXE линкер потом это PSP загрузит в исполняемый файл, несмотря на то, что линковка в .EXE. При модели памяти tiny и линковки .COM сначала загружается PSP, потом код, а потом данные. Модель памяти small и линковка .COM точка входа в программу должна быть на 100h байтах, при этом линкер не с корректирует адрес элементов сегмента данных, поэтому они буду загружены на 100h байт дальше. Если линковать .EXE объектник в котором указана модель памяти small и явно не загнать
Код:
mov ax, @data
mov ds,ax

то в ds будет находится непонятно что. Т.е. ассемблер только сделает метки где начинается сегмент данных, кода и где расположен стек. В cs адрес будет загружен системой, ds и ss не будут изменятся.

 
 
 
 Re: Hello world
Сообщение13.06.2013, 13:25 
xmaister в сообщении #736248 писал(а):
Если указать модель памяти tiny, то ассемблер зарезервирует первые 100h байт под PSP.

Модель говорят ассемблеру, какие будут сегменты и что в них будет находится. Директива "org 100h" говорит ассемблеру: "это место будет в памяти по адресу 100h (в сегменте кода)". Это заставит ассемблер правильно проставлять адреса (по умолчанию он считает, что первая инструкция находится по адресу 0).

xmaister в сообщении #736248 писал(а):
Далее, если линковать .EXE линкер потом это PSP загрузит в исполняемый файл, несмотря на то, что линковка в .EXE.

Ни ассемблер, ни линкер не знают, что такое PSP и никуда его загружать не будут. PSP формируется системой в памяти при загрузке программы. Система записывает его в первые 100h байт некоторого сегмента в памяти. В случае COM система в тот же сегмент загрузит весь COM-файл, а адрес этого сегмента будет записан в cs. В случае EXE адрес сегмента с PSP будет записан в ds, а сам код будет загружен в другой сегмент, начиная с адреса 0 (поэтому для EXE не надо писать "org 100h") -- это будет cs.

EXE можно делать в любой модели. COM только в tiny (вы знаете почему).

xmaister в сообщении #736248 писал(а):
При модели памяти tiny и линковки .COM сначала загружается PSP, потом код, а потом данные.

Да.

xmaister в сообщении #736248 писал(а):
Модель памяти small и линковка .COM

Низя.

xmaister в сообщении #736248 писал(а):
Если линковать .EXE объектник в котором указана модель памяти small и явно не загнать
Код:
mov ax, @data
mov ds,ax

то в ds будет находится непонятно что.

Верно в том смысле, что там будет не сегмент данных, который вам нужен. Но и не мусор: там будет сегмент, в котором записан PSP.

 
 
 
 Re: Hello world
Сообщение14.06.2013, 17:29 
Аватара пользователя
lena7 в сообщении #736262 писал(а):
xmaister в сообщении #736248 писал(а):
Модель памяти small и линковка .COM

Низя.

Я имел ввиду, что написать .model small а потом линковать в .COM никто не запрещает. Как я понял с Ваших слов линкер склеит DGROUP и _TEXT описанных в объектнике и не станет делать поправку на загрузку PSP.
lena7 в сообщении #736262 писал(а):
Верно в том смысле, что там будет не сегмент данных, который вам нужен. Но и не мусор: там будет сегмент, в котором записан PSP.

Я когда смотрел дебуггер, адрес в ds до и после
Код:
mov ax,@data
mov ds,ax
отличается, соотвественно смещение msg до и после
Код:
mov ax,@data
mov ds,ax
0108 и 0008 соответсвенно. Я думал что обратится к элементу сегмента можно только задав адрес сегмента и смещение конкретного байта и только так. А тут получается можно двумя способоми обратится к строке msg: Если не инициализировать сегмент данных то ds:0108, а если инициализировать, то ds:0008. :facepalm: Я думал что сегменты изолированы друг от друга и сегмент ничего не знает про другие сегменты...

 
 
 
 Re: Hello world
Сообщение14.06.2013, 20:11 
xmaister в сообщении #736648 писал(а):
Я думал что сегменты изолированы друг от друга и сегмент ничего не знает про другие сегменты...

Сегменты могут перекрываться.

 
 
 
 Re: Hello world
Сообщение15.06.2013, 01:00 
xmaister в сообщении #736648 писал(а):
Я думал что обратится к элементу сегмента можно только задав адрес сегмента и смещение конкретного байта и только так.

Разумеется. Вот только 8086 имеет 20-битную шину адреса, а оперирует 16-битными значениями. Откуда еще 4 бита берутся? Ответ: в сегментном регистре лежит адрес начала сегмента, сдвинутый на 4 бита вправо. И когда вы адресуете память, указывая сегментный регистр и смещение, физический адрес вычисляется следующим образом: значение сегментного регистра сдвигается на 4 разряда влево и к нему прибавляется смещение.

Поэтому сегмент 0008 лежит, начиная со 128-го байта. И

MOV DX, 0000
MOV AX, 0008
MOV DS, AX
MOV AL, [DX]

загрузит в AL байт по адресу 128, а код

MOV DX, 0080
MOV AX, 0000
MOV DS, AX
MOV AL, [DX]

загрузит в AL байт по адресу... тоже 128!

 
 
 [ Сообщений: 49 ]  На страницу Пред.  1, 2, 3, 4  След.


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group