С Новым годом! Форум программистов, компьютерный форум, киберфорум
Assembler для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.93/29: Рейтинг темы: голосов - 29, средняя оценка - 4.93
56 / 2 / 0
Регистрация: 19.10.2015
Сообщений: 98
1

Работа с памятью: адресация выделенной области памяти

06.02.2017, 17:11. Показов 5656. Ответов 14

Author24 — интернет-сервис помощи студентам
Привет, ребят! Допустим я создал (выделил) какой-то участок памяти (функция 48h).. Вооот И мне очень хотелось бы его как-то адресовать (в моем понимании адресовать - значит обращаться к нужному мне участку выделенной памяти и, при необходимости его изменять). По сути это просто буфер, в который я бы хотел запихивать данные, но я никак не пойму, как к нему обратиться.. Пробовал
Assembler
1
2
3
4
5
6
mov byte ptr [buffer], 20    ;хочу занести в первый байт двадцатку, но вместо этого просто изменяется значение переменной 
                                         ;buffer....
;........
;........
buffer dw ?
end LP
Подскажите, пожалуйста, как быть! А я пока попробую сам найти ответ)))
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
06.02.2017, 17:11
Ответы с готовыми решениями:

Работа с памятью, выделенной malloc
Доброго времени суток! Есть следующая проблема: Выделяем кусок памяти из кучи: void...

Почему в данном случае работа с заранее выделенной памятью медленнее чем с динамической?
Написал функцию которая на основе списка выделяет память и при каждом вызове возвращает указатель...

Разница между выделенной памятью и общей памятью графического процессора?
Здравствуйте! Купил и установил себе видеокарту GTX 1060 6Gb. При просмотре её производительности...

Почему у массивов типа char может быть утечка памяти, а у указателей char с выделенной памятью - нет?
Тут будет утечка памяти: #include<iostream> using namespace std; int main() { char name;...

14
3408 / 1827 / 489
Регистрация: 28.02.2015
Сообщений: 3,696
06.02.2017, 18:51 2
Цитата Сообщение от NEWd Посмотреть сообщение
(функция 48h
Функция, что она Вам возвращает?
1
56 / 2 / 0
Регистрация: 19.10.2015
Сообщений: 98
06.02.2017, 19:01  [ТС] 3
По идее функция возвращает адрес созданного блока памяти
0
3408 / 1827 / 489
Регистрация: 28.02.2015
Сообщений: 3,696
06.02.2017, 19:24 4
Цитата Сообщение от NEWd Посмотреть сообщение
По идее функция возвращает адрес созданного блока памяти
Вот оно.
Функция возвращает сегментный адрес, грузите его в сегментный регистр, ну а дальше как обычно в модели small.
2
56 / 2 / 0
Регистрация: 19.10.2015
Сообщений: 98
06.02.2017, 19:49  [ТС] 5
Хех! А у меня то tiny)) Но я нашел один вариант! Хотя это очень странно, но я смог оперировать с этим адресом с помощью stos.. А странность в том, что у меня после команды stos значение ax загружается не только по адресу ES:DI, но и по адресу ds:DI. Почему так я ума не приложу! Ведь копируется только в ES! Почему вдруг скопировалось еще и в DS? Хотя мне это очень помогло.. Но тут явно что-то не так..

Добавлено через 3 минуты
Стой, стой! Сегментный! Значит это не смещение, а целый сегмент?! Что-то я тогда не понимаю.. Зачем тогда указывать размер в BX, если все равно выделяется целый сегмент? Или выделяется кол-во параграфов из BX, считая от начала сегмента? Вот сейчас, честно говоря, запутался совсем)))
0
Asm/C++/Delphi/Py/PHP/VBA
6750 / 1997 / 231
Регистрация: 14.12.2014
Сообщений: 4,200
Записей в блоге: 12
07.02.2017, 00:31 6
Цитата Сообщение от NEWd Посмотреть сообщение
А странность в том, что у меня после команды stos значение ax загружается не только по адресу ESI, но и по адресу dsI. Почему так я ума не приложу
Такого быть не может вообще никак. Ну разве что DS=ES
Код в студию, чтобы не гадать на кофейной гущи.
Название модели - tiny, small и т.д. - это всё условно.

Assembler
1
2
3
4
5
6
7
8
mov ah,48h
mov bx,СколькоНадоПамятиБлокамиПо16байт
int 21h
jc Облом
 
mov es,ax
mov byte ptr es:[0],20  ; записать в первый выделенный байт 20
mov byte ptr es:[Buffer],20  ; это неправильно, т.к. смещение буфера заточено под сегмент CS (в модели tiny)
А вообще, проге изначально выделяется вся память. Т.е. надо юзать не 48h, а 4Ah.

Типа такого:
Assembler
1
2
3
4
5
6
7
8
9
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
.model tiny
.code
.startup
 
BufSize         =       1024            ; размер буфера должен быть кратен 16 байтам
 
BufOfs          =       (TheEnd-@Startup+100h+15) and 0FFF0h    ; смещение буфера относительно cs, ds (с выравниванием по 16 байтам)
 
                mov     ah,4Ah
                mov     bx,(BufOfs+BufSize)/16
                int     21h             ; меняем размер блока памяти, выделенный программе (адрес буфера + длина буфера)
                jc      LowMemory
 
                mov     ax,cs
                add     ax,BufOfs/16    ; смещение буфера относительно cs, ds (с выравниванием по 16 байтам)
                mov     es,ax           ; es = сегмент буфера
 
                mov     byte ptr es:[0],20      ; один вариант записи в буфер
                mov     es:Buffer,21            ; второй вариант записи в буфер
 
                ret
 
        LowMemory:
                mov     ah,9
                lea     dx,mLowMemory
                int     21h
 
                ret
 
mLowMemory      db      'Too low memory :(',13,10,'$'
 
        TheEnd:                         ; конец программы
 
org     0                               ; чтобы буфер начинался со смещения 0
Buffer          db      BufSize dup (?)
 
end
Ну или:
Assembler
1
2
3
4
5
6
7
8
9
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
.model tiny
.code
.startup
 
BufSize         =       1024            ; размер буфера должен быть кратен 16 байтам
 
BufOfs          =       (TheEnd-@Startup+100h+15) and 0FFF0h    ; смещение буфера относительно cs, ds (с выравниванием по 16 байтам)
 
                mov     ax,ds:[2]       ; сегмент после программы (последний выделенный программе сегмент + 1)
                mov     dx,cs           ; сегмент кода
                sub     ax,dx           ; кол-во параграфов, выделенных программе
                cmp     ax,(BufOfs+BufSize)/16  ; достаточно ли свободной памяти?
                jb      LowMemory
 
                add     dx,BufOfs/16    ; получение сегмента буфера
                mov     es,dx           ; es = сегмент буфера
 
                mov     byte ptr es:[0],20      ; один вариант записи в буфер
                mov     es:Buffer,21            ; второй вариант записи в буфер
 
                ret
 
        LowMemory:
                mov     ah,9
                lea     dx,mLowMemory
                int     21h
 
                ret
 
mLowMemory      db      'Too low memory :(',13,10,'$'
 
        TheEnd:                         ; конец программы
 
org     0                               ; чтобы буфер начинался со смещения 0
Buffer          db      BufSize dup (?)
 
end
1
19 / 187 / 0
Регистрация: 17.06.2013
Сообщений: 2,163
07.02.2017, 08:36 7
Цитата Сообщение от NEWd Посмотреть сообщение
А странность в том, что у меня после команды
Понимаете вообще, если иметь дело с ассемблером, к примеру в Pascal Delphi.
То надо сначало, перед работая с регистрами, начало скопировать то что в них было, и после использования вернуть это на место. Мне почему то всегда так приходится... А как, почему, я не спрашивался.
У вас по моему называется... Что то вроде попытки написать стек.
1
Модератор
Эксперт по электронике
8541 / 4393 / 1651
Регистрация: 01.02.2015
Сообщений: 13,649
Записей в блоге: 9
07.02.2017, 08:46 8
Ixmil, то, о чём вы говорите - соглашение об использовании регистров в конкретном компиляторе.
1
19 / 187 / 0
Регистрация: 17.06.2013
Сообщений: 2,163
07.02.2017, 10:14 9
Цитата Сообщение от NEWd Посмотреть сообщение
(в моем понимании адресовать - значит обращаться к нужному мне участку выделенной памяти и, при необходимости его изменять)
Ну это как то так:

Mov EAX, [EBX];

Цитата Сообщение от NEWd Посмотреть сообщение
По сути это просто буфер, в который я бы хотел запихивать данные, но я никак не пойму, как к нему обратиться.. Пробовал
Я сам писал, алгоритм длинной строковой переменой. И оказалось спотыкался, на таких простых вопросах, на которых не ожидал. А потому пришол к выводу. Что ассемблер существует, для написания таких небольших подфункций, но сами функции, из них состоят. И как то думается что должно быть так.

Добавлено через 19 минут
Цитата Сообщение от ФедосеевПавел Посмотреть сообщение
Ixmil, то, о чём вы говорите - соглашение об использовании регистров в конкретном компиляторе.
Ну я бы сказал, что я сказал о самой такой общей необходимости. Которая при том то затронет, что то то нет.

Добавлено через 1 час 7 минут
Цитата Сообщение от NEWd Посмотреть сообщение
Что-то я тогда не понимаю.. Зачем тогда указывать размер в BX, если все равно выделяется целый сегмент?
Но в принципе, я отвечу, не слишком осознавая вопрос, но предопределяя его сопутствующие.
Всякие недокументированные команды, я бы вообще сбросил со счетов, и писал бы длиннее но без них.
А если вам городят о наикротчайшем коде, от того с повышенным КПД. То знаете есть такие иллюзии.
Когда одно кажется не тем, что на деле. И КПД определить - как то очень сложно, а не просто.
0
3408 / 1827 / 489
Регистрация: 28.02.2015
Сообщений: 3,696
07.02.2017, 11:07 10
Цитата Сообщение от Jin X Посмотреть сообщение
А вообще, проге изначально выделяется вся память.
Формат СОМ, да забирает всю память, а вот для ЕХЕ формата, память выделяется в зависимости от двух значений в заголовке программы MinAlloc MaxAlloc:
0A-0B Number of paragraphs of additional memory that the program will need. This is the equivalent of the BSS size in a Unix program. The program can't be loaded if there isn't at least this much memory available to it.
0C-0D Maximum number of paragraphs of additional memory. Normally, the OS reserves all the remaining conventional memory for your program, but you can limit it with this field.
Миниатюры
Работа с памятью: адресация выделенной области памяти  
1
3408 / 1827 / 489
Регистрация: 28.02.2015
Сообщений: 3,696
07.02.2017, 11:34 11
Цитата Сообщение от NEWd Посмотреть сообщение
Стой, стой! Сегментный! Значит это не смещение, а целый сегмент?! Что-то я тогда не понимаю.. Зачем тогда указывать размер в BX, если все равно выделяется целый сегмент? Или выделяется кол-во параграфов из BX, считая от начала сегмента? Вот сейчас, честно говоря, запутался совсем)))
Функция возвращает сегментный адрес выделеного блока памяти, Загрузив его в сегмент, блок памяти можно использовать также как и сегмент данных т.е. DS : [offset X] или ES : [offset X]

Добавлено через 10 минут
Ixmil,
1)Давайте не будем путать чистый ассемблер и встроенный. Несмотря на их схожесть. При работе со встроенным асмом, основную работу за Вас выполняет компилятор ЯВУ, в читстом всё должен продумать кодер.
2)Это не что то вроде... Память может понадобится в большенстве случаях, поэтому не видя кода говорить о каких-то стеках нельзя.
1
Asm/C++/Delphi/Py/PHP/VBA
6750 / 1997 / 231
Регистрация: 14.12.2014
Сообщений: 4,200
Записей в блоге: 12
07.02.2017, 14:45 12
Цитата Сообщение от Ixmil Посмотреть сообщение
То надо сначало, перед работая с регистрами, начало скопировать то что в них было, и после использования вернуть это на место. Мне почему то всегда так приходится... А как, почему, я не спрашивался.
У вас по моему называется... Что то вроде попытки написать стек.
Их не копировать надо, а сохранять (в стеке обычно... хотя это и есть копирование, но так никто не выражается) и восстанавливать. В 32-битных программах это ebx, esi, edi. Ну и ebp, esp, разумеется (обычно это делается в прологах/эпилогах). И то, если они изменяются только.
p.s. В 64-битных кроме rbx, rsi, rdi, rbp, rsp сохраняются ещё r12..r15, xmm6..xmm15, если кому интересно...

Цитата Сообщение от NEWd Посмотреть сообщение
Стой, стой! Сегментный! Значит это не смещение, а целый сегмент?! Что-то я тогда не понимаю.. Зачем тогда указывать размер в BX, если все равно выделяется целый сегмент? Или выделяется кол-во параграфов из BX, считая от начала сегмента? Вот сейчас, честно говоря, запутался совсем)))
Что значит "выделяется целый сегмент"? Сегмент - это НЕ некая область памяти фиксированного размера, он может иметь размер 16 байт, а может быть сотни килобайт. И в регистре BX ты как раз указываешь размер этого сегмента. Потом тебе возвращается в регистре AX сегментный адрес, который ты записываешь в ES. Память в DOS организована в виде пары Сегмент:Смещение, линейный адрес получается как Сегмент*16 + Смещение, т.е. Адреса 1234h:0 = 1000h:2340h = 1200h:340h = 1230h:40h, так же как 0F000h:0FFF0h = 0FFFFh:0. Именно поэтому раз тебе выделяется вся память (оставшаяся доступная), твоя задача - лишь проверить, достаточно ли памяти тебе выделено. А дальше, если, например, твои переменные хранятся по смещению 200h, то ты можешь спокойно адресовать их через ds:200h, а можешь записать в ES значение DS (или CS в COM-программе) + 20h и адресовать через es:0. Второй случай есть смысл использовать, если тебе нужно много памяти, например, 64Кб. Или больше, тогда придётся менять ES несколько раз (или использовать DS, FS, GS, например). А если у тебя прога занимает 1Кб кода (+256 байт на PSP), то до конца сегмента кода (CS=DS=ES при старте программы) остаётся ещё 64256 байт (62,75 Кб), и вполне можно юзать привычные "переменные", а-ля:
Assembler
1
2
3
4
5
6
.data
Buffer db 1024 dup (?)
 
.code
mov Buffer,ax
ret
Или без .data:
Assembler
1
2
3
4
mov Buffer,ax
ret
 
Buffer db 1024 dup (?)
Цитата Сообщение от Constantin Cat Посмотреть сообщение
Формат СОМ, да забирает всю память, а вот для ЕХЕ формата, память выделяется в зависимости от двух значений в заголовке программы MinAlloc MaxAlloc
Да это понятно. Но когда компилишь прогу, то по умолчанию там (в 0C-0D) указывается максимум. В fasm есть директива heap, а вот в tasm/masm с этим сложно. В tasm вообще ничего нет, а в masm (link.exe) даже параметр /heap никакого эффекта не оказывает...

Добавлено через 22 минуты
Кстати, забыл сказать про стек. В com-программе стек находится в конце сегмента кода (SS=CS).
Если памяти выделено >= 64Кб, то sp=0FFFEh. Если меньше, то sp<0FFFEh. Таким образом, для надёжности при использовании большого кол-ва памяти внутри сегмента кода (т.е. если максимум нужно заюзать 64Кб – размер кода – 256 на PSP – размер стека) нужно делать проверку:
Assembler
1
2
  cmp sp,(offset Buffer)+BufSize+StackSize
  jb LowMemory
где Buffer - метка начала буфера (без org 0, разумеется), BufSize - размер буфера, StackSize - размер стека (256 байт нормально).
В общем вот так:
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
.model tiny
.code
.startup
 
BufSize         =       32768           ; размер буфера (в байтах)
StackSize       =       256             ; размер стека (в байтах)
 
                cmp     sp,(offset Buffer)+BufSize+StackSize
                jc      LowMemory
 
                lea     di,Buffer
                mov     cx,(BufSize+1)/2
                xor     ax,ax
                rep stosw               ; инициализируем буфер нулями
 
                mov     Buffer,20       ; запись в буфер
 
                ret                     ; здесь можно делать ret, т.к. в стек при загрузке проги записывается 0, а sp мы не меняли
 
        LowMemory:
                mov     ah,9
                lea     dx,mLowMemory
                int     21h
 
                ret                     ; здесь можно делать ret, т.к. в стек при загрузке проги записывается 0, а sp мы не меняли
 
mLowMemory      db      'Too low memory :(',13,10,'$'
 
Buffer          db      BufSize dup (?)
 
end
В приведённом мной выше коде ошибка: я забыл учесть стек. Как-то вот так это должно быть:
Assembler
1
2
3
4
5
6
7
8
9
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
.model tiny
.code
.startup
 
BufSizeParas    =       4096            ; размер буфера в параграфах (по 16 байт)
StackSize       =       256             ; размер стека (в байтах, должен быть кратен 16 байтам для корректных расчётов)
 
BufOfs          =       (TheEnd-@Startup+100h+StackSize+15) and 0FFF0h  ; смещение буфера относительно cs, ds (с выравниванием по 16 байтам)
 
                lea     sp,StackStart
 
                mov     ah,4Ah
                mov     bx,BufOfs/16+BufSizeParas
                int     21h             ; меняем размер блока памяти, выделенный программе (адрес буфера + длина буфера)
                jc      LowMemory
 
                mov     ax,cs
                add     ax,BufOfs/16    ; смещение буфера относительно cs, ds (с выравниванием по 16 байтам)
                mov     es,ax           ; es = сегмент буфера
 
                xor     di,di
                mov     cx,BufSizeParas*8
                xor     ax,ax
                rep stosw               ; инициализируем буфер нулями
 
                mov     byte ptr es:[0],20      ; один вариант записи в буфер
                mov     es:Buffer,21            ; второй вариант записи в буфер
 
                int     20h             ; ret делать нельзя, т.к. в стеке у нас нет 0 (мы же изменили sp)
 
        LowMemory:
                mov     ah,9
                lea     dx,mLowMemory
                int     21h
 
                int     20h             ; ret делать нельзя, т.к. в стеке у нас нет 0 (мы же изменили sp)
 
mLowMemory      db      'Too low memory :(',13,10,'$'
 
        TheEnd:                         ; конец программы
        org BufOfs
        StackStart:                     ; начало стека (он растёт вниз, при записи первого слова значение будет записано по адресу -2 относительно текущего)
 
org     0                               ; чтобы буфер начинался со смещения 0
Buffer          label   byte
 
end
или...
Assembler
1
2
3
4
5
6
7
8
9
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
.model tiny
.code
.startup
 
BufSizeParas    =       4096    ; размер буфера в параграфах (по 16 байт)
StackSize       =       256             ; размер стека (в байтах, должен быть кратен 16 байтам для корректных расчётов)
 
BufOfs          =       (TheEnd-@Startup+100h+StackSize+15) and 0FFF0h  ; смещение буфера относительно cs, ds (с выравниванием по 16 байтам)
 
                lea     sp,StackStart
 
                mov     ax,ds:[2]       ; сегмент после программы (последний выделенный программе сегмент + 1)
                mov     dx,cs           ; сегмент кода
                sub     ax,dx           ; кол-во параграфов, выделенных программе
                cmp     ax,BufOfs/16+BufSizeParas       ; достаточно ли свободной памяти?
                jb      LowMemory
 
                add     dx,BufOfs/16    ; получение сегмента буфера
                mov     es,dx           ; es = сегмент буфера
 
                xor     di,di
                mov     cx,BufSizeParas*8
                xor     ax,ax
                rep stosw               ; инициализируем буфер нулями
 
                mov     byte ptr es:[0],20      ; один вариант записи в буфер
                mov     es:Buffer,21            ; второй вариант записи в буфер
 
                int     20h             ; ret делать нельзя, т.к. в стеке у нас нет 0 (мы же изменили sp)
 
        LowMemory:
                mov     ah,9
                lea     dx,mLowMemory
                int     21h
 
                int     20h             ; ret делать нельзя, т.к. в стеке у нас нет 0 (мы же изменили sp)
 
mLowMemory      db      'Too low memory :(',13,10,'$'
 
        TheEnd:                         ; конец программы
        org BufOfs
        StackStart:                     ; начало стека (он растёт вниз, при записи первого слова значение будет записано по адресу -2 относительно текущего)
 
org     0                               ; чтобы буфер начинался со смещения 0
Buffer          label   byte
 
end
1
56 / 2 / 0
Регистрация: 19.10.2015
Сообщений: 98
07.02.2017, 20:05  [ТС] 13
Так, кажется большинство вопросов отпали!) Но появился очень интересный: что вообще делает функция 48h? Выделяет памяти за пределами программы, тем самым увеличивая доступную память? Непонятно также зачем использовать 4Ah, если она просто расширяет блок? Можно ведь контролировать размер блока при его создании, а максимальный размер блока, как я понимаю, превысить нельзя. (4Ah нужна скорей для сокращения блока, отведенного для программы) А насчет кода - нет смысла его прикреплять. Обычная комка (на данном этапе). Блок нужен для функции 0Ah (ввод строки). Мог бы сделать простой массив, но зачем-то решил заморочиться))).. Воот.. А теперь у меня уже спортивный интерес. Как видно эти функции - явный пробел в знаниях!
0
Asm/C++/Delphi/Py/PHP/VBA
6750 / 1997 / 231
Регистрация: 14.12.2014
Сообщений: 4,200
Записей в блоге: 12
07.02.2017, 21:14 14
Лучший ответ Сообщение было отмечено NEWd как решение

Решение

Цитата Сообщение от NEWd Посмотреть сообщение
Но появился очень интересный: что вообще делает функция 48h? Выделяет памяти за пределами программы, тем самым увеличивая доступную память? Непонятно также зачем использовать 4Ah, если она просто расширяет блок?
Если проге выделена вся доступная память, то 48h больше ничего не выделит. Если ты видишь, что ah=48h/int 21h вернула в BX значение > 0, значит есть свободный блок (небольшой, скорее всего) по адресу ниже программы. 4Ah может как сокращать, так и расширять.
Для функции 0Ah ничего не нужно, никаких блоков памяти выделять.
Если ты делаешь прогу формата COM, у тебя памяти будет предостаточно. И уж 80 байт тебе точно хватит на ввод строки.
Если EXE, то там требуемый объём будет заложен в заголовок, тем более можно не беспокоиться...
1
56 / 2 / 0
Регистрация: 19.10.2015
Сообщений: 98
07.02.2017, 21:21  [ТС] 15
Спасибо за помощь!)
0
07.02.2017, 21:21
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
07.02.2017, 21:21
Помогаю со студенческими работами здесь

Могут ли два приложения пользоваться одной и той же выделенной памятью?
День добрый! С помощью FileMapping, в ActiveX компоненте, создана область в памяти куда копируются...

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

Распределение и адресация памяти
Доброго времени суток. Уважаемые гуру и ассемблеристы , требуется подсказка начинающему...

Сегментная адресация памяти
Здравствуйте, читаю небольшой материал про процессор 8086 и появившийся в нем режим сегментации...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru