- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
; %ch - x1, %cl - y1, %dh - x2, %dl - y2 ;
drawline:
push %a
push %b
push %c
push %d
push %e
mov %al %dh
sub %al %ch
call @abs
mov %ah %al ; ah - dX ;
mov %al %dl
sub %al %cl
call @abs
neg %al ; al - -dY ;
mov %bh FFh ; bh - signX;
mov %bl FFh ; bl - signY ;
cmp %ch %dh
jgz @.S1
neg %bh
.S1:
cmp %cl %dl
jgz @.S2
neg %bl
.S2:
mov %el %ah
add %el %al ; el - error ;
push %d
call @drawpixel
pop %d
.loop:
cmp %ch %dh
jnz @.L1
cmp %cl %dl
jnz @.L1
jmp @.loop_end
.L1:
push %c
call @drawpixel
pop %c
mov %eh %el
cmp %eh %al
jng @.L2
add %el %al
add %ch %bh
.L2:
cmp %eh %ah
jgz @.loop
add %el %ah
add %cl %bl
jmp @.loop
.loop_end:
pop %e
pop %d
pop %c
pop %b
pop %a
ret
Как-будто в винде и линуксе фиксапов нет...
Тем более после прихода ASLR, который закидывает экзешник хрен пойми куда.
З.Ы. В линуксе pic, ему можно не патчить.
В Висте появилось ASLR, и снова стали собирать экзешники с фиксапами, чтобы их можно было «закинуть хрен знает куда».
В ebx теперь лежит адрес @1. К адресам данных теперь можно добавить ebx-@1, тогда в экзешник они лягут без фиксапов. Возврата не будет, потому что адрес возврата из стека вытолкнули.
Да, колл без рета. Такое вирусы любили использовать, потому что их никто патчить не будет.
З.Ы. Хотя не, там другие инварианты на старте, экзешник поди сам сегментные регистры выставляет.
Для EXE он должен сделать какую-то интеллектуальную работу, а COM просто загружает.
Но когда EXE только появился, он различал именно по расширению. А потом перестал.
Почему?
COMMAND.COM и FORMAT.COM нельзя переименовывать не сломав к хуям примерно всё, хотя они уже и повылазили за 64K -- размер сегмента.
А вдруг COM файл начнется с MZ?
А не начнется, потому что MZ это
Прекрасный Реймонд Чен поясняет
Винда их нормально запускает как приложение Win32, несмотря на расширение .com.
Тупо, что оно 32 бита (майки наговнокодили и десятый год не могут перевестись в 64) но всё же оно .exe
но всё, что он делает, это запускет .exe. Этакий трамполин.
наверное для совместимости с visual studio 4.0
Однако, для таких экзешников, если они влезают в 64К, был псевдоконвертор: он перед сигнатурой MZ прилеплял загрузчик в формате com-файла, который читал заголовок экзешника, рассовывал его секции по сегментам памяти и патчил фиксапы, а потом передавал управление. Я не помню, решали ли там задачу двойного потребления памяти.
Программы, сконвертированные псевдоконвертором, можно было восстановить в exe. Была программа com2exe, написанная... да, Фабрисом Белларом, кем же ещё.
If Force Far Calls is off, the compiler uses the NEAR call models for any procedures or functions within the file being compiled.
тоесь нихуа не large
Кстати, в ТП тип pointer и типизированные указатели (хоть на данные, хоть на функции) всегда far. Нельзя объявить переменную, чтобы она хранила near-указатель. Поэтому и к «ближним» процедурам и функциям нельзя применить операцию @ и их нельзя передать в другую процедуру или функцию как аргумент.
В качестве параметра f можно передать только far-функцию.
Т. е. в сишке можно было так:
Если модификатор far/near не указан, то размер указателя выбирался по текущей модели.
По умолчанию far-указатели и на код, и на данные были в модели large.
Получается, что модель ТП больше всего похожа на модель large, но с исключением: неэкспортируемые процедуры и функции по умолчанию были near (но они были неполноценными, потому что даже в пределах модуля на них нельзя было брать указатель).
У каждого компилятора могут быть свои модели
В некоторых компиляторах отсутствовала модель тайни, для получения com-файла нужно было выбирать смолл и указывать дополнительные параметры, чтобы стек не создавался.
deneg.net
raboty.net
schastya.net
mozgov.net
Ответить
Думаешь я помню их названия?
Вроде что-то среднее, с far для данных и near для кода.
Каждый модуль, перечисляемый в uses, линкер клал в отдельный сегмент.
Можно было объявлять функции с директивой near, чтобы получить более оптимальный код (near- и short-джампы были rip-based и не требовали фиксапов), но поскольку все указатели были только far, то адреса near-функций нельзя было класть в указатели и куда-нибудь передавать, также их нельзя было экспортировать в другие модули.
Вопрос: нафига?
Ответ: call near будет rip-based, поэтому фиксапа не будет. Такой заменой получается pic.
В тройке не было модульной системы, поэтому для использования библиотек применяли чёрную магию:
https://govnokod.ru/19045
Я ходил в некоторый аналог дворца пионеров, и там был turbo или borland паскаль (отличался набором либ, всяким OWL, вроде оверлеями и пр), на тот момент это было очень продвинуто.
Турбо влазил на дискету, а борманд -- нет.
Кстати, IDE сама была под дос (подозреваю турбо вижн) а писать можно было и под винду и OWL. Все помнят эти кнопочки с зеленой галочкой и красным крестиком, да?
Были ещё пиратские сборки «на двух дискетах», которые я терпеть не мог. В конце 1990-х уже ни у кого не было 20-мегабайтных винчестеров, чтобы так экономить.
В пакете Борланд были те же самые компиляторы, которые были в раздельных пакетах Турбо, и даже те же самые библиотеки. Разница была только в том, что в Борланд это всё засунули в один установочный пакет.
Правда, в Борланд дополнительно положили ещё одну версию IDE и компилятора. Обычные turbo.exe и tpc.exe были под реальный режим, а bp.exe и bpc.exe (которые клали только в Борланд, но не клали в Турбо) работали в защищённом (через бормандовскую прослойку RTM+DPMI), так что могли использовать больше оперативки (это было важно при компиляции огромных программ). Эти компиляторы поддерживали одни и те же языковые конструкции и генерировали одинаковый код, и библиотеки были одинаковыми, разница была только в доступной компилятору и IDE оперативке.
Если ты студень, то тебе хватит турбы для лаб.
Если ты пишешь коммерческий софт, то тебе уже не скомпилица турбой, и нужен борманд. Думаю, так.
32-битными стали только вторые Дельфи.
В BP7.0 и в Delphi 1.0 были 16-битные rtm.exe и dpmi16bi.ovl. Можно было генерировать код под реальный режим и под защищённый режим с 16-битными сегментами, как в Windows 3.x. В этом же режиме работали консольные компиляторы bpc.exe и dcc.exe и IDE bp.exe.
Во вторые Дельфи и в Борманд C++ 4.x (в пятые Борманд C++ стопудово) уже клали консольные компиляторы, работающие в защищённом режиме с 32-битным flat-сегментом. К ним прилагался 32rtm.exe и dpmi32bi.ovl.
>менять заголо
помнишь ANSI.SYS? Поди, через него можно было?
Славилась доброй душой
(с)
ANSI.SYS про другое. Он интерпретировал эскейп-последовательности в стандартном выходном потоке.
Это, пардон, кокая? Там была только ``command.com`` же.
консоль (cmd.exe, Win32API Console API) были тока в NT.
Или я вру?
>ANSI.SYS про другое.
А знаешь, как в прыщах программы устанавливают тайтл у окна эмулятора терминала?
FAR, который был чистым portable executable для win32 console API, в Win95 работал.
https://en.wikipedia.org/wiki/Cmd.exe
моя память -- тоже. Но мы можем врать (четверть века прошла всё таки), так что я наверное и правда скачаю на досуге, да посмотрю.
Так что с тайтлами xterm, putty и пр? Знаешь, как их устанавливают?
>far
хм.. и пправда
ааа!!
вот как дело было
https://en.wikipedia.org/wiki/Windows_Console#Windows_9x
но cmd.exe там не было
Но Win32 console API точно было. Я точно помню программы в формате portable executable, которые в DOS не работали, а в Win95 работали. Помню, что в Win95 console API были реализованы все функции с суффиксом A (ANSI), а вот с функциями с суффиксом W (Wide, что означает поддержку UTF-16) была беда, были реализованы не все, поэтому некоторые консольные программы, предназначенные для NT, в Win95 могли не работать.
Но API было, хотя и урежанное (работало оно в v86, как я там выше дал ссылку). Иными словами, любая соснольная херня в win9x всегда порождала 16-ти битный процесс, как я понял.
И ты прав на счет "A": в 9x всё было "A", а в NT -- "W".
Отсюда у нас TEXT() и прочие хаки
Ядром системы был 32-битный VMM.vxd (virtual memory manager).
Часть функций WinAPI была реализована вызовом функций DOS и BIOS, сидящих в V86, посредством vxd-драйверов. Поэтому Win95 мог использовать досовские драйвера и резидентные программы, запущенные через autoexec.bat и config.sys.
К некоторому железу уже были прямые 32-битные драйвера в обход DOS и BIOS.
Win95 умел загружать и 32-битные drv, и 16-битные от Win 3.x.
WinAPI был в двух вариантах: 16-битный (на основе API Win 3.x) и 32-битный, как в NT (но функций с суффиксом W было мало).
Некоторые функции одного API вызывали из-под себя функции другого API, так что при работе любой программы использовались и 16-битные, и 32-битные сегменты.
В NT эти интерфейсы изолировали. Там придумали WOW (Windows on Windows). Win32 стал основным интерфейсом, а 16-битный API реализовали через него. И драйверов 16-битных не стало.
Да, в Windows 3.1 уже были 32-битные vxd-драйвера, хотя я не знаю, зачем, ведь ядро и API были 16-битными.
а не machine?
икарус прикинь, про кишки винды девяностопятой целую книжку написили
https://vtda.org/books/Computing/OperatingSystems/Inside_Windows_95_Adrian_King_1994.pdf
Нам играют живые "Битлз"
И стареющий Эдриан Пол Кинг.
Там есть много всратого прыгания между 16 и 32 режимами, наивная вера в OLE, еще более наинвые diff провайдеры для потрфеля (который не взлетел), ода реестру, и довольно крутые многоуровневая архитетура сети, где петузы умудрились утоптать в одну абстракцию NetBIOS, TCP/IP, IPX/SPX, и еще черта в ступе
А еще про модемы, принтеры, видяху ("плоский" драйвер SVGA), в общем такой как Руссинович про NT, только про Чикаго и на 400 страниц вместо 2K
В 95 все VxD были защищенные (хз, могли-ли они быть 16-ти битными, но они точно были не под реальный режим), и
Windows не мог использовать досовые драйвера.
Досовые драйвера (и всякие TSR) загружались (вместе с autoexec.bat и config.sys) в каждый DOS VM, для досовских программ.
То-есть досовские прогиаммы могли чото там использовать, а виндовые -- нет.
В отличие от 3.0, где хождение например на диск было реализовано через досове прерывание (и могло всё завесить), в Win95 уже появился IFS с редиректорами.
Досовым TSR винда могла "эмулировать" устройства (через записи в IO map и исключения) но не наоборот
Windows не мог использовать досовые драйвера.
Всё сложнее. В одном VXD могли быть вперемешку 16-битные и 32-битные сегменты. Формат LE такое поддерживал. Да, и 16-битные, и 32-битные были в защищённом режиме.
DOS в Win95 был в двух ролях:
1. Тот, который стартовал до запуска Windows. Да, в Win95 загрузка начиналась с запуска IO.SYS.
2. Тот, который сидит в виртуальных машинах (VDM).
Так вот Win95, как и 3.1, посредством VXD могла использовать досовские драйвера, загруженные в первом ДОС. А второй ДОС был как бы в песочнице: он мог использовать драйвера Windows посредством VxD, т. е. всё противоположно первому.
Тогда в этом нет ничего страшного.
В protected mode можно легко запустить 16-ти битный защищенный (aka 286) код: это же просто битик в дескрипторе сегмента, говорящий о том, какой это код.
Вот код реального режима запустить нельзя, потому что он насрет тебе в порты ввода/вывода или в память.
>Так вот Win95, как и 3.1, посредством VXD могла использовать досовские драйвера, загруженные в первом ДОС
А как это работало?
Ну вот я написал драйвер, который TSR, который перехватывает прерывание, и эмулирует диск "D" который на самом деле на луне.
Пусть я даже написал VxD, который может его дернуть.
А как он будет в реальном режиме-то работать? Как он будет ходить в IO порты?
Мне кажется, что в отличии от 3.0, в Win95 dos ВСЕГДА работал в V86
Что, не спрашиваете? Говорите, вам похуй?
Ну и похуй, всё равно расскажу.
VMM это ядро, а VxD это модуль ядра, да?
Так вот сисколы (там они назывались сервисами) можно было вызвать:
1. Через INT 2F (как в Win16)
2. Через API Kernel.dll, который потом слал запрос через call gate (в отличие от **nix и NT использовалось НЕ прерывание, а до SYSENTER было еще лет пятандцать)
Второй способ делал вас переносимвм на NT. Первый -- нет конечно
Само собой, был и третий способ -- прерывания доса или биоса, но это только для реальных программ под DOS VM
Необычно, да?
Через этот API VxD регистрировали у VMM себя.
Раньше надо было явно в system.ini писать, а с W95 стало можно динамически.
Причем если ты хочешь предоставлять API для для других, то ты должен получить ID. А если только колбеки то не должен: просто регся.
Там описываются, например, как они делали thunkи.
Часть кода была 16ти битной, и из 32х битного надо было вызывать его, а часть была наоборот.
Ну там была мысль всё сделать 32 (спиздив код из NT) но это было бы тяжело по памяти (NT требовало 16 метров, а в 95 -- 4), потому часть осталась 16-ти битной.
И был thunk генератор в SDK, который превращал вызовы 32 в вызовы 16, укорачивая там инты в стеке, меня значения регистров, и пр.
А потом оказадлось, что 16битнеый код не реентерабелен (не только код приложений, но и системы), и они запилили вокруг него а-ля GIL
Win16Mutex
В доках по Win32s вроде они были описаны.
Flat thunk для вызова 16 из 32.
Generic thunk и universal thunk для вызова 32 из 16. Последний используется в Win32s, generic — в NT и 95.
https://i.postimg.cc/XYTHRFXx/image.png
В Win95 консоль была реализована через жопу. В Win 3.x был vdm.exe (или как-то так), который умел рисовать чёрное окошко для досовских программ.
В Win95 решили для рисования консоли взять за основу этот код из Win 3.x, чтобы не писать с нуля. Поэтому в Win95 при запуске любого приложения win32 console API прицепом загружалась VDM, что создавало дополнительную нагрузку.
cmd.exe действительно был только в NT и в OS/2.
Правда, в ту пору консоль считалась устаревшей, легаси для старого говна, а светлое будущее должно было состоять примерно из MFC.
Иронично, что 90% софта у ту пору было как раз таки под дос
Да, были, но поддерживали только одну консоль (в отличии от NT)
https://i.postimg.cc/rmt3fcJK/image.png
Я тебя понял. Оригинальный ANSI.SYS писался под голый ДОС и про сервисы, предоставляемые VXD, не знал. Но если его дописать, то такую функцию реализовать можно.
DPMI играл две роли:
1. Реализовывал переходники между программой защищённого режима и функциями DOS и BIOS.
2. Реализовывал собственный API (INT 31h), в котором были функции для управления виртуальной памятью вроде VirtualAlloc, функций для работы с линейными адресами и сегментами, управления защитой, работы с обработчиками прерываний и т. п., так что в прикладной программе можно было обходиться без низкоуровневого кода.
RTM же реализовывал дополнительную библиотеку.
16-битный RTM мумулировал API OS/2 для соснольных приложений: часть функций DOSCALLS.DLL, VIOCALLS.DLL, KBDCALLS.DLL.
32-битный RTM мумулировал Win32 для соснольных приложений: часть функций kernel32.dll, user32.dll, advapi32.dll.
Для запуска ФАРа из голого DOS посредством 32RTM этих функций было недостаточно. Рантайм, позволяющий запустить ФАР из DOS, появился позже:
https://www.japheth.de/HX.html
Но даже тот рантайм, что был у Борланда, позволял собирать двойные приложения защищённого режима, которые могли работать и в голом DOS, и в винконсоли. К таким приложениям относились борландовские компиляторы и Турбо Дебагер. Даже IDA выпускалась в виде такого приложения.
Почему 16-битный RTM мумулирует функции OS/2, а не Windows? Да потому что у 16-битных Windows (Win 3.x) не было консольного API.
К слову, такой рантайм был не только у Борланда. Был Pharlap TNT DOS extender с похожим API. Его ещё использовали какие-то компиляторы (Metaware High C++ вроде).
Я не знаю реальные примеры программ, которые бы использовали расширитель Pharlap для Windows. Когда появился Win32s, стали писать программы под Win32 API и запускать через него. Например, древний 32-битный Фотошоп спокойно запускался не только в NT и в Win95, но и в Win 3.x через Win32s.
Как именно реализовывался, не знаю. Где-то в VMM, вероятно.
https://i.postimg.cc/L4yfWpb8/image.png
Найди на картинке DPMI Server.
Для поддержки массивов более 64К в 16-битном коде нужно было крутить сегмент. В защищённом режиме для этого нужно плодить записи в LDT или крутить базу.
В Борманд Паскале сделали проще: не стали реализовывать модель Huge. Т. е. писали код так, чтобы массивы и объекты укладывались в 64К. Если нужно было больше 64К, использовали датастримы: в библиотеке Турбовижн были классы, предоставляющие интерфейс к памяти как к файлу. Или использовали связанные списки и деревья, у которых каждый узел аллоцировался отдельно.
Tiny. As you might guess, this is the smallest of the memory
models. All four segment registers (CS, DS, 55, ES) are set to the
same address, so you have a total of 64K for all of your code, data,
and stack. Near pointers are always used. Tiny model programs
can be converted to .COM format by linking with the It option.
Small. The code and data segments are different and don't overlap, so you have 64K of code and 64K of data and stack. Near
pointers are always used.
Medium. Far pointers are used for code, but not for data. As a
result, data plus stack are limited to 64K, but code can occupy up
to 1 MB.
Compact. The inverse of medium: Far pointers are used for data,
but not for code. Code is then limited to 64K, while data has a 1
MB range.
Large. Far pointers are used for both code and data, giving both a
1 MB range.
Huge. Far pointers are used for both code and data. Borland C++
normally limits the size of all static data to 64K; the huge memory
model sets aside that limit, allowing data to occupy more than
64K.
> 1 MB range
ура, стандартная библиотека.
кстати при чётных y2 почему-то не рисует, интересно почему
Выбирай, что тебе ближе.
https://www.youtube.com/watch?v=_dydTviK8gY