unixforum.org
Как принудительно выгрузить всю исполняемую программу в оперативную память в Linux?
Обсуждение настройки и работы сервисов, резервирования, сетевых настроек и вопросов безопасности ОС.
Модератор: SLEDopit
9 сообщений • Страница 1 из 1
astronom1987 Сообщения: 1145 ОС: MX Linux Контактная информация:
Как принудительно выгрузить всю исполняемую программу в оперативную память в Linux?
Итак, как мы знаем когда начинается процесс запуска какого-то приложения (допустим в Linux), то в оперативной памяти оказывается не все оно, а только некая его часть, которая предусмотренная программистами для нормального использования нашей программы. А когда пользователь обаращатся какой-то ее функциональности, которая ранее не была подгружена, то тогда программа эта делает автоматически загружая дополнительнные данные из жесткого диска в оперативку для продолжения нормальной ее работы. Такой подход кажется вполне приемлемым особенно, что касается программ с большой функциональностью таких как скажем libreoffice.org .
Но допустим, что у меня есть не очень большая программа, которую мне позарез нужно, чтобы она все свои компоненты функицональности выгруажала в оперативную память сразу.
Как же в Linux добиться этого? Не запускать же ради одного приложения всю систему оперативную память учитывая даже то, что такая возможность в Linux есть?
Спасибо сказали:
yoricI Сообщения: 2395 ОС: gentoo fluxbox
Re: Как принудительно выгрузить всю исполняемую программу в оперативную память в Linux?
Сообщение yoricI » 16.06.2021 06:30
Мне кажется, что никак, как написана программа, так и будет работать по своему плану. Ну можно потыкать в неё вручную, всю функциональность возбудить. А зачем, если не секрет?
15.06.2021 20:04
Не запускать же ради одного приложения всю систему оперативную память учитывая даже то, что такая возможность в Linux есть?
Вопрос по ОЗУ: выгрузка программы из памяти
Двоичные команды программы, загруженные в озу постепенно выгружаются из нее по мере их выполнения? Или вся программа целиком в двоичном виде остается там до конца ее выполнения?
Отслеживать
32.1k 19 19 золотых знаков 80 80 серебряных знаков 106 106 бронзовых знаков
задан 9 фев 2012 в 10:16
username76 username76
488 2 2 золотых знака 16 16 серебряных знаков 31 31 бронзовый знак
Однако вопрос. А по-конкретнее можно? Потому что вариантов ответа на такой простой вопрос очень много. Давайте конкретные условия.
9 фев 2012 в 10:21
Нет, программа выгружается только после окончания выполнения (а скорее, блок памяти просто помечается как не занятый)
9 фев 2012 в 10:53
3 ответа 3
Сортировка: Сброс на вариант по умолчанию
Единственный случай, когда они могут выгрузиться из ОЗУ, — это свопинг их страницы на жесткий диск. Но в виртуальной памяти они все равно остаются и при необходимости могут вернуться в ОЗУ. Но они все равно должны остаться в доступности для процессора. А вдруг где-то в последующей части программы стоит jmp на них?
Отслеживать
ответ дан 9 фев 2012 в 11:04
23.9k 2 2 золотых знака 38 38 серебряных знаков 69 69 бронзовых знаков
или когда плату озу вытянуть с мамки =)
9 фев 2012 в 12:41
Тогда, боюсь, это не будет иметь уже никакого значения ((((
9 фев 2012 в 12:45
я к тому что случай уже не единственный, а вообще неплохо бы послать @username76 Таненбаума
9 фев 2012 в 12:47
Почитаю, дайте полное название книги:)
9 фев 2012 в 13:17
Таненбаум «современные операционные системы»
9 фев 2012 в 13:19
Память для кода может выгружаться в следующих случаях:
- При освобождении библиотеки, если она больше не используется никаким процессом.
- При генерации кода «на лету» (JIT-компиляция) программа может освободить память, если этот код больше не нужен.
Автоматически нельзя выгружать код, потому что он выполняется не последовательно, а в нём есть ветвления, циклы и вызовы функций. Нельзя определить, может ли вызваться та или иная функция.
А почему тебя это беспокоит? Код занимает не так много места по-сравнению с данными, чтобы об этом думать.
Отслеживать
ответ дан 9 фев 2012 в 14:48
5,431 21 21 серебряный знак 32 32 бронзовых знака
В дополнение к ответу @mikillskegg, по секрету сообщу Вам, что иногда некоторые блоки команд даже не попадают в ОЗУ. Это называется позднее связывание или загрузка по требованию (on demand).
Если серьезно, то (м.б. кроме какой-нибудь экзотики) команды никогда не записываются на HDD. Если страничка с ними (при свопинге/пэйджинге) временно освобождается, то они повторно подкачиваются (при первом доступе к такой странице) не из swap, а из исходного экзешника.
Отслеживать
ответ дан 9 фев 2012 в 12:50
46.1k 6 6 золотых знаков 48 48 серебряных знаков 116 116 бронзовых знаков
Круто. А в ОЗУ команды откуда попадают, не с HDD? (Кроме какой-нибудь экзотики: флеш, cdrom. )
9 фев 2012 в 13:03
Конечно с HDD (флэш, cdrom. ) (локального или по сети (сетевая файловая система)). Речь о том, что в swap на HDD они не пишутся.
9 фев 2012 в 13:07
Вах, надо будет со всем этим при случае подробнее разобраться
9 фев 2012 в 13:23
> Если серьезно, то (м.б. кроме какой-нибудь экзотики) команды никогда не записываются на HDD. А если на HDD экзешник упакован например UPX?
10 фев 2012 в 17:17
@insolor, спасибо за хорошее замечание (раньше про это толком не знал). Про работу UPX можно почитать в man upx , IMHO другие упаковщики работают аналгично. Почитав этот man я понял, что исполняемый модуль, упакованный UPX распаковывает «себя» в память (если ОС позволит исполнять область данных) или во временный файл (очевидно потом делает execl()). Про свопинг исполняемой области данных не знаю, а с файлом очевидно, все как обычно (с точки зрения ОС). Про «экзотику», пардон, погорячился. Правильнее сказать «многие версии *nix и м.б. других ОС».
Как выгрузить программу из памяти
Чтобы выгрузить резидентную программу из памяти, необходимо сделать три вещи: закрыть открытые программой файлы и устройства, восстановить все перехваченные векторы прерываний, и наконец, освободить всю занятую программой память. Трудность может вызвать второй шаг, так как после нашего резидента могли быть загружены другие программы, перехватившие те же прерывания. Если в такой ситуации восстановить вектор прерывания в значение, которое он имел до загрузки нашего резидента, программы, загруженные позже, не будут получать управление. Более того, они не будут получать управление только по тем прерываниям, которые у них совпали с прерываниями, перехваченными нашей программой, в то время как другие векторы прерываний будут все еще указывать на их обработчики, что почти наверняка приведет к ошибкам. Поэтому, если хоть один вектор прерывания не указывает на наш обработчик, выгружать резидентную программу нельзя. Это всегда было главным вопросом, и спецификации AMIS и IBM ISP (см. предыдущую главу) являются возможным решением этой проблемы. Если вектор прерывания не указывает на нас, имеет смысл проверить, не указывает ли он на ISP-блок (первые два байта должны быть EBh 10h, а байты 6 и 7 — «K» и «B»), и, если это так, взять в качестве вектора значение из этого блока и т.д. Кроме того, программы могут изменять порядок, в котором обработчики одного и того же прерывания вызывают друг друга.
Последний шаг в выгрузке программы — освобождение памяти — можно выполнить вручную, вызывая функцию DOS 49h на каждый блок памяти, который программа выделяла через функцию 48h, на блок с окружением DOS, если он не освобождался при загрузке, и наконец, на саму программу. Однако есть способ заставить DOS сделать все это (а также закрыть открытые файлы и вернуть код возврата) автоматически, вызвав функцию 4Ch, объявив резидент текущим процессом. Посмотрим, как это делается на примере резидентной программы, занимающей много места в памяти. Кроме того, этот пример реализует все приемы, использующиеся для вызова функций DOS из обработчиков аппаратных прерываний, о которых рассказано в главе 5.8.3.
; scrgrb.asm ; Резидентная программа, сохраняющая изображение с экрана в файл. ; Поддерживается только видеорежим 13h (320x200x256) и только один файл. ; HCI: ; Нажатие Alt-G создает файл scrgrb.bmp в текущем каталоге с изображением, ; находившимся на экране в момент нажатия клавиши. ; Запуск с командной строкой /u выгружает программу из памяти ; API: ; Программа занимает первую свободную функцию прерывания 2Dh (кроме нуля) ; в соответствии со спецификацией AMIS 3.6 ; Поддерживаемые подфункции AMIS: 00h, 02h, 03h, 04h, 05h ; Все обработчики прерываний построены в соответствии с IBM ISP ; Резидентная часть занимает в памяти 1056 байт, если присутствует EMS, ; и 66 160 байт, если EMS не обнаружен .model tiny .code .186 ; для сдвигов и команд pusha/popa org 2Ch envseg dw ? ; сегментный адрес окружения org 80h cmd_len db ? ; длина командной строки cmd_line db ? ; командная строка org 100h ; COM-программа start: jmp initialize ; переход на инициализирующую часть ; Обработчик прерывания 09h (IRQ1) int09h_handler proc far jmp short actual_int09h_handler ; пропустить ISP old_int09h dd ? dw 424Bh db 00h jmp short hw_reset db 7 dup (0) actual_int09h_handler: ; начало собственно обработчика INT 09h pushf call dword ptr cs:old_int09h ; сначала вызвать старый ; обработчик, чтобы он завершил аппаратное ; прерывание и передал код в буфер pusha ; это аппаратное прерывание - надо push ds ; сохранить все регистры push es push 0040h pop ds ; DS = сегментный адрес области данных BIOS mov di,word ptr ds:001Ah ; адрес головы буфера ; клавиатуры, cmp di,word ptr ds:001Ch ; если он равен адресу ; хвоста, je exit_09h_handler ; буфер пуст, и нам делать нечего, mov ax,word ptr [di] ; иначе: считать символ, cmp ah,22h ; если это не G (скан-код 22h), jne exit_09h_handler ; выйти mov al,byte ptr ds:0017h ; байт состояния клавиатуры, test al,08h ; если Alt не нажата, jz exit_09h_handler ; выйти, mov word ptr ds:001Ch,di ; иначе: установить адреса головы ; и хвоста буфера равными, то есть ; опустошить его call do_grab ; подготовить BMP-файл с изображением mov byte ptr cs:io_needed, 1 ; установить флаг ; требующейся записи на диск cli call safe_check ; проверить, можно ли вызвать DOS, jc exit_09h_handler sti call do_io ; если да - записать файл на диск exit_09h_handler: pop es pop ds ; восстановить регистры рора iret ; и вернуться в прерванную программу int09h_handler endp hw_reset: retf ; Обработчик INT 08h (IRQ0) int08h_handler proc far jmp short actual_int08h_handler ; пропустить ISP old_int08h dd ? dw 424Bh db 00h jmp short hw_reset db 7 dup (0) actual_int08h_handler: ; собственно обработчик pushf call dword ptr cs:old_int08h ; сначала вызвать стандартный ; обработчик, чтобы он завершил ; аппаратное прерывание (пока оно ; не завершено, запись на диске невозможна) pusha push ds cli ; между любой проверкой глобальной переменной ; и принятием решения по ее значению - ; не повторно входимая область, прерывания ; должны быть запрещены cmp byte ptr cs:io_needed,0 ; проверить, je no_io_needed ; нужно ли писать на диск call safe_check ; проверить, jc no_io_needed ; можно ли писать на диск sti ; разрешить прерывания на время записи call do_io ; запись на диск no_io_needed: pop ds рора iret int08h_handler endp ; Обработчик INT 13h ; поддерживает флаг занятости INT 13h, который тоже надо проверять перед ; записью на диск int13h_handler proc far jmp short actual_int13h_handler ; пропустить ISP old_int13h dd ? dw 424Bh db 00h jmp short hw_reset db 7 dup (0) actual_int13h_handler: ; собственно обработчик pushf inc byte ptr cs:bios_busy ; увеличить счетчик занятости INT 13h cli call dword ptr cs:old_int13h pushf dec byte ptr cs:bios_busy ; уменьшить счетчик popf ret 2 ; имитация команды IRET, не восстанавливающая ; флаги из стека, так как обработчик INT 13h возвращает некоторые ; результаты в регистре флагов, а не в его копии, хранящейся ; в стеке. Он тоже завершается командой ret 2 int13h_handler endp ; Обработчик INT 28h ; вызывается DOS, когда она ожидает ввода с клавиатуры и функциями DOS можно ; пользоваться int28h_handler proc far jmp short actual_int28h_handler ; пропустить ISP old_int28h dd ? dw 424Вh db 00h jmp short hw_reset db 7 dup (0) actual_int28h_handler: pushf push di push ds push cs pop ds cli cmp byte ptr io_needed,0 ; проверить, je no_io_needed2 ; нужно ли писать на диск lds di,dword ptr in_dos_addr cmp byte ptr [di+1],1 ; проверить, ja no_io_needed2 ; можно ли писать на диск (флаг ; занятости DOS не должен быть больше 1) sti call do_io ; запись на диск no_io_needed2: pop ds pop di popf jmp dword ptr cs:old_int28h ; переход на старый ; обработчик INT 28h int28h_handler endp ; Процедура do_grab ; помещает в буфер палитру и содержимое видеопамяти, формируя BMP-файл. ; Считает, что текущий видеорежим - 13h do_grab proc near push cs pop ds call ems_init ; отобразить наш буфер в окно EMS mov dx,word ptr cs:buffer_seg mov es,dx ; поместить сегмент с буфером в ES и DS mov ds,dx ; для следующих шагов процедуры mov ax,1017h ; Функция 1017h - чтение палитры VGA mov bx,0 ; начиная с регистра палитры 0, mov сх,256 ; все 256 регистров mov dx,BMP_header_length ; начало палитры в BMP int 10h ; видеосервис BIOS ; перевести палитру из формата, в котором ее показывает функция 1017h ; (три байта на цвет, в каждом байте 6 значимых бит), ; в формат, используемый в BMP-файлах ; (4 байта на цвет, в каждом байте 8 значимых бит) std ; движение от конца к началу mov si,BMP_header_length+256*3-1 ; SI- конец 3-байтной палитры mov di,BMP_header_length+256*4-1 ; DI - конец 4-байтной палитры mov сх,256 ; СХ - число цветов adj_pal: mov al,0 stosb ; записать четвертый байт (0) lodsb ; прочитать третий байт shl al,2 ; масштабировать до 8 бит push ax lodsb ; прочитать второй байт shl al,2 ; масштабировать до 8 бит push ax lodsb ; прочитать третий байт shl al,2 ; масштабировать до 8 бит stosb ; и записать эти три байта pop ax ; в обратном порядке stosb pop ax stosb loop adj_pal ; Копирование видеопамяти в BMP. ; В формате BMP строки изображения записываются от последней к первой, так что ; первый байт соответствует нижнему левому пикселю cld ; движение от начала к концу (по строке) push 0A000h pop ds mov si,320*200 ; DS:SI - начало последней строки на экране mov di,bfoffbits ; ES:DI - начало данных в BMP mov dx,200 ; счетчик строк bmp_write_loop: mov cx,320/2 ; счетчик символов в строке rep movsw ; копировать целыми словами, так быстрее sub si,320*2 ; перевести SI на начало предыдущей строки dec dx ; уменьшить счетчик строк, jnz bmp_write_loop ; если 0 - выйти из цикла call ems_reset ; восстановить состояние EMS ; до вызова do_grab ret do_grab endp ; Процедура do_io ; создает файл и записывает в него содержимое буфера do_io proc near push cs pop ds mov byte ptr io_needed,0 ; сбросить флаг требующейся ; записи на диск call ems_init ; отобразить в окно EMS наш буфер mov ah,6Ch ; Функция DOS 6Ch mov bx,2 ; доступ - на чтение/запись mov cx,0 ; атрибуты - обычный файл mov dx,12h ; заменять файл, если он существует, ; создавать, если нет mov si,offset filespec ; DS:SI - имя файла int 21h ; создать/открыть файл mov bx,ax ; идентификатор файла - в ВХ mov ah,40h ; Функция DOS 40h mov cx,bfsize ; размер BMP-файла mov ds,word ptr buffer_seg mov dx,0 ; DS:DX - буфер для файла int 21h ; запись в файл или устройство mov ah,68h ; сбросить буфера на диск int 21h mov ah,3Eh ; закрыть файл int 21h call ems_reset ret do_io endp ; Процедура ems_init, ; если буфер расположен в EMS, подготавливает его для чтения/записи ems_init proc near cmp dx,word ptr ems_handle ; если не используется EMS cmp dx,0 ; (EMS-идентификаторы начинаются с 1), je ems_init_exit ; ничего не делать mov ax,4700h ; Функция EMS 47h int 67h ; сохранить EMS-контекст mov ax,4100h ; Функция EMS 41h int 67h ; определить адрес окна EMS mov word ptr buffer_seg,bx ; сохранить его mov ax,4400h ; Функция EMS 44h mov bx,0 ; начиная со страницы 0, int 67h ; отобразить страницы EMS в окно mov ax,4401h inc bx int 67h ; страница 1 mov ax,4402h inc bx int 67h ; страница 2 mov ax,4403h inc bx int 67h ; страница 3 ems_init_exit: ret ems_init endp ; Процедура ems_reset ; восстанавливает состояние EMS ems_reset proc near mov dx,word ptr cs:ems_handle cmp dx,0 je ems_reset_exit mov ax,4800h ; Функция EMS 48h int 67h ; восстановить EMS-контекст ems_reset_exit: ret ems_reset endp ; Процедура safe_check ; возвращает CF = 0, если в данный момент можно пользоваться функциями DOS, ; и CF = 1, если нельзя safe_check proc near push es push cs pop ds les di,dword ptr in_dos_addr ; адрес флагов занятости DOS, cmp word ptr es:[di],0 ; если один из них не 0, pop es jne safe_check_failed ; пользоваться DOS нельзя, cmp byte ptr bios_busy,0 ; если выполняется прерывание 13h, jne safe_check_failed ; тоже нельзя clc ; CF = 0 ret safe_check_failed: stc ; CF = 1 ret safe_check endp in_dos_addr dd ? ; адрес флагов занятости DOS io_needed db 0 ; 1, если надо записать файл на диск bios_busy db 0 ; 1, если выполняется прерывание INT 13h buffer_seg dw 0 ; сегментный адрес буфера для файла ems_handle dw 0 ; идентификатор EMS filespec db 'scrgrb.bmp',0 ; имя файла ; Обработчик INT 2Dh hw_reset2D: retf int2Dh_handler proc far jmp short actual_int2Dh_handler ; пропустить ISP old_int2Dh dd ? dw 424Bh db 00h jmp short hw_reset2D db 7 dup (0) actual_int2Dh_handler: ; собственно обработчик db 80h,0FCh ; начало команды CMP АН,число mux_id db ? ; идентификатор программы, je its_us ; если вызывают с чужим АН - это не нас jmp dword ptr cs:old_int2Dh its_us: cmp al,06 ; функции AMIS 06h и выше jae int2D_no ; не поддерживаются cbw ; AX = номер функции mov di,ax ; DI = номер функции shl di,1 ; * 2, так как jumptable - таблица слов jmp word ptr cs:jumptable[di] ; переход на обработчик функции jumptable dw offset int2D_00,offset int2D_no dw offset int2D_02,offset int2D_no dw offset int2D_04,offset int2D_05 int2D_00: ; проверка наличия mov al,0FFh ; этот номер занят mov cx,0100h ; номер версии программы 1.0 push cs pop dx ; DX:DI - адрес AMIS-сигнатуры mov di,offset amis_sign iret int2D_no: ; неподдерживаемая функция mov al,00h ; функция не поддерживается iret unload_failed: ; сюда передается управление, если хоть один из векторов ; прерываний был перехвачен кем-то после нас mov al,01h ; выгрузка программы не удалась iret int2D_02: ; выгрузка программы из памяти cli ; критический участок push 0 pop ds ; DS - сегментный адрес таблицы векторов прерываний mov ax,cs ; наш сегментный адрес ; проверить, все ли перехваченные прерывания по-прежнему указывают на нас, ; обычно достаточно проверить только сегментные адреса (DOS не загрузит другую ; программу с нашим сегментным адресом) cmp ax,word ptr ds:[09h*4+2] jne unload_failed cmp ax,word ptr ds:[13h*4+2] jne unload_failed cmp ax,word ptr ds:[08h*4+2] jne unload_failed cmp ax,word ptr ds:[28h*4+2] jne unload_failed cmp ax,word ptr ds:[2Dh*4+2] jne unload_failed push bx ; адрес возврата - в стек push dx ; восстановить старые обработчики прерываний mov ax,2509h lds dx,dword ptr cs:old_int09h int 21h mov ax,2513h lds dx,dword ptr cs:old_int13h int 21h mov ax,2508h lds dx,dword ptr cs:old_int08h int 21h mov ax,2528h lds dx,dword ptr cs:old_int28h int 21h mov ax,252Dh lds dx,dword ptr cs:old_int2Dh int 21h mov dx,word ptr cs:ems_handle ; если используется EMS cmp dx,0 je no_ems_to_unhook mov ax,4500h ; функция EMS 45h int 67h ; освободить выделенную память jmp short ems_unhooked no_ems_to_unhook: ems_unhooked: ; собственно выгрузка резидента mov ah,51h ; Функция DOS 51h int 21h ; получить сегментный адрес PSP ; прерванного процесса (в данном случае ; PSP - копии нашей программы, ; запущенной с ключом /u) mov word ptr cs:[16h],bx ; поместить его в поле ; "сегментный адрес предка" в нашем PSP pop dx ; восстановить адрес возврата из стека pop bx mov word ptr cs:[0Ch],dx ; и поместить его в поле mov word ptr cs:[0Ah],bx ; "адрес перехода при ; завершении программы" в нашем PSP pop bx ; BX = наш сегментный адрес PSP mov ah,50h ; Функция DOS 50h int 21h ; установить текущий PSP ; теперь DOS считает наш резидент текущей программой, а scrgrb.com /u - ; вызвавшим его процессом, которому и передаст управление после вызова ; следующей функции mov ax,4CFFh ; Функция DOS 4Ch int 21h ; завершить программу int2D_04: ; получить список перехваченных прерываний mov dx,cs ; список в DX:BX mov bx,offset amis_hooklist iret int2D_05: ; получить список "горячих" клавиш mov al,0FFh ; функция поддерживается mov dx,cs ; список в DX:BX mov bx,offset amis_hotkeys iret int2Dh_handler endp ; AMIS: сигнатура для резидентной программы amis_sign db "Cubbi. " ; 8 байт db "ScrnGrab" ; 8 байт db "Simple screen grabber using EMS",0 ; AMIS: список перехваченных прерываний amis_hooklist db 09h dw offset int09h_handler db 08h dw offset int08h_handler db 28h dw offset int28h_handler db 2Dh dw offset int2Dh_handler ; AMIS: список "горячих" клавиш amis_hotkeys db 1 db 1 db 22h ; скан-код клавиши (G) dw 08h ; требуемые флаги клавиатуры dw 0 db 1 ; конец резидентной части ; начало процедуры инициализации initialize proc near jmp short initialize_entry_point ; пропустить различные варианты выхода без установки резидента, ; помещенные здесь потому, что на них передают управление ; команды условного перехода, имеющие короткий радиус действия exit_with_message: mov ah,9 ; функция вывода строки на экран int 21h ret ; выход из программы already_loaded: ; если программа уже загружена в память cmp byte ptr unloading,1 ; если мы не были вызваны с /u je do_unload mov dx,offset already_msg jmp short exit_with_message no_more_mux: ; если свободный идентификатор INT 2Dh не найден mov dx,offset no_more_mux_msg jmp short exit_with_message cant_unload1: ; если нельзя выгрузить программу mov dx,offset cant_unload1_msg jmp short exit_with_message do_unload: ; выгрузка резидента: при передаче управления сюда АН содержит ; идентификатор программы - 1 inc ah mov al,02h ; AMIS-функция выгрузки резидента mov dx,es ; адрес возврата mov bx,offset exit_point ; в DX:BX int 2Dh ; вызов нашего резидента через мультиплексор push cs ; если управление пришло сюда - ; выгрузка не произошла pop ds mov dx,offset cant_unload2_msg jmp short exit_with_message exit_point: ; если управление пришло сюда - push cs ; выгрузка произошла pop ds mov dx,offset unloaded_msg push 0 ; чтобы сработала команда RET для выхода jmp short exit_with_message initialize_entry_point: ; сюда передается управление в самом начале cld cmp byte ptr cmd_line[1],'/' jne not_unload cmp byte ptr cmd_line[2],'u' ; если нас вызвали с /u jne not_unload mov byte ptr unloading,1 ; выгрузить резидент not_unload: mov ah, 9 mov dx,offset usage ; вывод строки с информацией о программе int 21h mov ah,-1 ; сканирование от FFh до 01h more_mux: mov al,00h ; функция AMIS 00h - ; проверка наличия резидента int 2Dh ; мультиплексорное прерывание cmp al,00h ; если идентификатор свободен, jne not_free mov byte ptr mux_id,ah ; вписать его сразу в код обработчика, jmp short next_mux not_free: mov es,dx ; иначе - ES:DI = адрес AMIS-сигнатуры ; вызвавшей программы mov si,offset amis_sign ; DS:SI = адрес нашей сигнатуры mov cx,16 ; сравнить первые 16 байт, repe cmpsb jcxz already_loaded ; если они не совпадают, next_mux: dec ah ; перейти к следующему идентификатору, jnz more_mux ; если это 0 free_mux_found: cmp byte ptr unloading, 1 ; и если нас вызвали для выгрузки, je cant_unload1 ; а мы пришли сюда - программы нет в ; памяти, cmp byte ptr mux_id,0 ; если при этом mux_id все еще 0, je no_more_mux ; идентификаторы кончились ; проверка наличия устройства ЕММХХХХ0 mov dx,offset ems_driver mov ax,3D00h int 21h ; открыть файл/устройство jc no_emmx mov bx,ax mov ax,4400h int 21h ; IOCTL: получить состояние файла/устройства jc no_ems test dx,80h ; если старший бит DX = 0, ЕММХХХХ0 - файл jz no_ems ; выделить память под буфер в EMS mov ax,4100h ; функция EMS 41h int 67h ; получить адрес окна EMS mov bp,bx ; сохранить его пока в ВР mov ax,4300h ; Функция EMS 43h mov bx,4 ; нам надо 4 * 16 Кб int 67h ; выделить EMS-память (идентификатор в DХ), cmp ah,0 ; если произошла ошибка (нехватка памяти?), jnz ems_failed ; не будем пользоваться EMS, mov word ptr ems_handle,dx ; иначе: сохранить идентификатор ; для резидента mov ax,4400h ; Функция 44h - отобразить mov bx,0 ; EMS-страницы в окно int 67h ; страница 0 mov ax,4401h inc bx int 67h ; страница 1 mov ax,4402h inc bx int 67h ; страница 2 mov ax,4403h inc bx int 67h ; страница 3 mov dx,offset ems_msg ; вывести сообщение об установке в EMS jmp short ems_used ems_failed: no_ems: ; если EMS нет или он не работает, mov ah,3Eh int 21h ; закрыть файл/устройство ЕММХХХХ0, no_emmx: ; занять общую память mov ah,9 mov dx,offset conv_msg ; вывод сообщения об этом int 21h mov sp,length_of_program+100h+200h ; перенести стек mov ah,4Ah ; Функция DOS 4Ah next_segment = length_of_program+100h+200h+0Fh next_segment = next_segment/16 ; такая запись нужна только для ; WASM, остальным ассемблерам это ; можно было записать в одну строчку mov bx,next_segment ; уменьшить занятую память, оставив ; текущую длину нашей программы + 100h ; на PSP +200h на стек int 21h mov ah,48h ; Функция 48h - выделить память bfsize_p = bfsize+0Fh bfsize_p = bfsize_p/16 mov bx,bfsize_p ; размер BMP-файла 320x200x256 в 16-байтных int 21h ; параграфах ems_used: mov word ptr buffer_seg,ax ; сохранить адрес буфера для резидента ; скопировать заголовок BMP-файла в начало буфера mov cx,BMP_header_length mov si,offset BMP_header mov di,0 mov es,ax rep movsb ; получить адреса флага занятости DOS и флага критической ошибки (считая, что ; версия DOS старше 3.0) mov ah,34л ; Функция 34h - получить флаг занятости int 21h dec bx ; уменьшить адрес на 1, чтобы он указывал ; на флаг критической ошибки, mov word ptr in_dos_addr,bx mov word ptr in_dos_addr+2,es ; и сохранить его для резидента ; перехват прерываний mov ax,352Dh ; АН = 35h, AL = номер прерывания int 21h ; получить адрес обработчика INT 2Dh mov word ptr old_int2Dh,bx ; и поместить его в old_int2Dh mov word ptr old_int2Dh+2,es mov ax,3528h ; AH = 35h, AL = номер прерывания int 21h ; получить адрес обработчика INT 28h mov word ptr old_int28h,bx ; и поместить его в old_int28h mov word ptr old_int28h+2,es mov ax,3508h ; AH = 35h, AL = номер прерывания int 21h ; получить адрес обработчика INT 08h mov word ptr old_int08h,bx ; и поместить его в old_int08h mov word ptr old_int08h+2,es mov ax,3513h ; AH = 35h, AL = номер прерывания int 21h ; получить адрес обработчика INT 13h mov word ptr old_int13h,bx ; и поместить его в old_int13h mov word ptr old_int13h+2,es mov ax,3509h ; AH = 35h, AL = номер прерывания int 21h ; получить адрес обработчика INT 09h mov word ptr old_int09h,bx ; и поместить его в old_int09h mov word ptr old_int09h+2,es mov ax,252Dh ; AH = 25h, AL = номер прерывания mov dx,offset int2Dh_handler ; DS:DX - адрес обработчика int 21h ; установить новый обработчик INT 2Dh mov ax,2528h ; AH = 25h, AL = номер прерывания mov dx,offset int28h_handler ; DS:DX - адрес обработчика int 21h ; установить новый обработчик INT 28h mov ax,2508h ; AH = 25h, AL = номер прерывания mov dx,offset int08h_handler ; DS:DX - адрес обработчика int 21h ; установить новый обработчик INT 08h mov ax,2513h ; AH = 25h, AL = номер прерывания mov dx,offset int13h_handler ; DS:DX - адрес обработчика int 21h ; установить новый обработчик INT 13h mov ax,2509h ; AH = 25h, AL = номер прерывания mov dx,offset int09h_handler ; DS:DX - адрес обработчика int 21h ; установить новый обработчик INT 09h ; освободить память из-под окружения DOS mov ah,49h ; Функция DOS 49h mov es,word ptr envseg ; ES = сегментный адрес окружения DOS int 21h ; освободить память ; оставить программу резидентной mov dx,offset initialize ; DX - адрес первого байта за концом ; резидентной части int 27h ; завершить выполнение, оставшись ; резидентом initialize endp ems_driver db 'EMMXXXX0',0 ; имя EMS-драйвера для проверки ; текст, который выдает программа при запуске: usage db 'Простая программа для копирования экрана только из' db ' видеорежима 13h',0Dh,0Ah db ' Alt-G - записать копию экрана в scrgrb.bmp' db 0Dh,0Ah db ' scrgrb.com /u - выгрузиться из памяти',0Dh,0Ah db '$' ; тексты, которые выдает программа при успешном выполнении: ems_msg db 'Загружена в EMS',0Dh,0Ah,'$' conv_msg db 'He загружена в EMS',0Dh,0Ah,'$' unloaded_msg db 'Программа успешно выгружена из памяти',0Dh,0Ah,'$' ; тексты, которые выдает программа при ошибках: already_msg db 'Ошибка: Программа уже загружена',0Dh,0Ah,'$' no_more_mux_msg db 'Ошибка: Слишком много резидентных программ' db 0Dh,0Ah,'$' cant_unload1_msg db 'Ошибка: Программа не обнаружена в памяти',0Dh,0Ah,'$' cant_unload2_msg db 'Ошибка: Другая программа перехватила прерывания' db 0Dh,0Ah,'$' unloading db 0 ; 1, если нас запустили с ключом /u ; BMP-файл (для изображения 320x200x256) BMP_header label byte ; файловый заголовок BMP_file_header db "BM" ; сигнатура dd bfsize ; размер файла dw 0,0 ; 0 dd bfoffbits ; адрес начала BMP_data ; информационный заголовок BMP_info_header dd bi_size ; размер BMP_info_header dd 320 ; ширина dd 200 ; высота dw 1 ; число цветовых плоскостей dw 8 ; число бит на пиксель dd 0 ; метод сжатия данных dd 320*200 ; размер данных dd 0B13h ; разрешение по X (пиксель на метр) dd 0B13h ; разрешение по Y (пиксель на метр) dd 0 ; число используемых цветов (0 - все) dd 0 ; число важных цветов (0 - все) bi_size = $-BMP_info_header ; размер BMP_info_header BMP_header_length = $-BMP_header ; размер обоих заголовков bfoffbits = $-BMP_file_header+256*4 ; размер заголовков + размер палитры bfsize = $-BMP_file_header+256*4+320*200 ; размер заголовков + ; размер палитры + размер данных length_of_program = $-start end start
В этом примере, достаточно сложном из-за необходимости избегать всех возможностей повторного вызова прерываний DOS и BIOS, добавилась еще одна мера предосторожности — сохранение состояния EMS-памяти перед работой с ней и восстановление в исходное состояние. Действительно, если наш резидент активируется в тот момент, когда какая-то программа работает с EMS, и не выполнит это требование, программа будет читать/писать уже не в свои EMS-страницы, а в наши. Аналогичные предосторожности следует предпринимать всякий раз, когда вызываются функции, затрагивающие какие-нибудь глобальные структуры данных. Например: функции поиска файлов используют буфер DTA, адрес которого надо сохранить (функция DOS 2Fh), затем создать собственный (функция DOS 1Ah) и в конце восстановить DTA прерванного процесса по сохраненному адресу (функция 1Ah). Таким образом надо сохранять/восстанавливать состояние адресной линии А20 (функции XMS 07h и 03h), если резидентная программа хранит часть своих данных или кода в области HMA, сохранять состояние драйвера мыши (INT 33h, функции 17h и 18h), сохранять информацию о последней ошибке DOS (функции DOS 59h и 5D0Ah), и так с каждым ресурсом, который затрагивает резидентная программа. Писать полноценные резидентные программы в DOS сложнее всего, но, если не выходить за рамки реального режима, это — самое эффективное средство управления системой и реализации всего, что только можно реализовать в DOS.
Выгрузка приложения из памяти
Кто-ниб может подсказать, такая ситуация (и так кждый день!): сидит пользователь, чет делает, тыкается между приложениями, винда расфасовывает это все в памяти, ну тут места не хватило, ниче страшного загрузим в файл подкачки, загрузили, тут еще пользователь чет делал и. тут решил закрыть приложение . и все, система упала нафиг, ну то есть не совсем упала а стала чет там думать, перефасовывать, записывать, стирать. Я так думаю, что винда затирает файл подкачки, но зачем. Нельзя что-ли было заголовок какой-ниб затереть и все не парится, приложение же закрывается, пусть там настройки возьмет если надо, зачем весь то ковырять. просто бесит
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:
Файл в base 64, выгрузка и загрузка в памяти приложения
Интересует возможность реализации: Есть dll файл, можно ли его hex код преобразовать в base64.
Выгрузка DLL из памяти
Такая беда, есть две библиотеки, в каждой есть функция выгрузки её из памяти. И тут дело с D3D.
Выгрузка из памяти и время
Делаю активити, на котором пользователь отвечает на вопросы(тест с вариантами ответа). Под это.
Выгрузка прерывания из памяти
Доброго времени суток! программа не выгружается из памяти, просмотрел много чего в интернете, но.
2528 / 830 / 36
Регистрация: 28.09.2011
Сообщений: 4,319
Сообщение от GoodLife
а стала чет там думать, перефасовывать, записывать, стирать.
только это все при закрытии приложения происходит типа из оперативки на жесткий и оперативка при этом виновата менее всего
прямая дорога тебе — проц и жесткий