Начинающий

Applications development, KoOS API questions
  • Вообще-то, значение Интерфейсов сложно объяснить словами, каждый для себя его воспринимает по-разному.
    Если задуматься о самом значении слова Интерфейс, то это нечто соединяющие (связующие) какой-то объект с другим объектом.
    Программист не тот, кто постоянно пишет КОД, а тот кто сможет понять чужой КОД!!!
  • Интерфейсы используются в тех языках, авторы которых не смогли решить проблему множественного наследования и, перестраховавшись, разрешили его только от интерфейсов.
  • Не понимаю, как динамические библиотеки используют память? Типа как
    mov eax,[var]
    var dd 123
    Они же динамические. Как они определяют куда писать/читать.
    Чем больше сыра, тем больше в нём дыр. Чем больше дыр, тем меньше в нём собственно сыра. Значит, чем больше сыра, тем меньше сыра!
  • GerdtR wrote:Они же динамические. Как они определяют куда писать/читать.
    Как в Windows такой код себя поведет не знаю. А в Колибри если сделать подобное, то сначала будет создаваться локальная копия всей бибилиотеки для конкретного приложения. И меняться будет данные в локальной версии библиотеки. Это расходует память, т. к. создается копия не только для переменных а и для програмного кода. Потому подобных ситуаций следует избегать, но во многих библиотеках они встречаються.
  • Т.е. мне лучше просто выделить динамически память и использовать её через указатель в качестве переменных? Кстати далёкие переходы тоже лучше не делать? Только относительные?
    Чем больше сыра, тем больше в нём дыр. Чем больше дыр, тем меньше в нём собственно сыра. Значит, чем больше сыра, тем меньше сыра!
  • GerdtR, при компиляции команды типа mov eax,[var] fasm генерирует код команды и запоминает, что на таком-то месте был адрес var. В двоичном формате это знание успешно игнорируется, но в более сложных форматах в той или иной форме есть список перемещаемых элементов aka relocations, в котором записано, что там-то и там-то находятся адреса. Загрузчик библиотеки уже знает, где именно в памяти размещена библиотека, и проходит по списку перемещаемых элементов, корректируя адреса. В результате после загрузки mov eax,[var] читает откуда надо.
    IgorA, неверно. Нет никакой локальной копии всей библиотеки для конкретного приложения.
    GerdtR, глобальных переменных действительно лучше избегать, но по причинам, не связанным с библиотеками: глобальные переменные, к которым много обращений, могут существенно усложнить выяснение "какая собака здесь порылась, что теперь у переменных какие-то странные значения"; с глобальными переменными обязательно будут проблемы, если к ним есть обращение из двух потоков параллельно. Глобальные константы - возможно, вычисляемые и записываемые один раз при инициализации, но не при работе - пожалуйста. И, между прочим, каждый адрес глобальной переменной - 4 байта в коде и лишняя запись в таблице перемещаемых элементов. Лучше использовать локальные переменные:

    Code: Select all

    include 'proc32.inc'
    proc MyAwesomeProc
    locals
    var1 dd ?
    var2 dd ?
    endl
    mov [var1],eax
    ret
    endp
    
    Для справки: это транслируется примерно в

    Code: Select all

    if used MyAwesomeProc
    MyAwesomeProc:
    push ebp
    mov ebp, esp
    sub esp, 8 ; allocate space for two dword variables
    mov [ebp-4], eax
    leave
    ret
    end if
    
    Локальные переменные создаются на стеке, для их адресации используется регистр ebp. Если регистров не хватает и очень хочется задействовать ebp для вычислений, то можно адресовать и напрямую через esp:

    Code: Select all

    proc MyAwesomeProc
    sub esp, 8 ; allocate space for two dwords
    virtual at esp
    .var1 dd ?
    .var2 dd ?
    end virtual
    mov [.var1], eax
    add esp, 8 ; restore the stack
    ret
    endp
    
    но тогда придётся очень внимательно следить за всеми операциями со стеком, которые сбивают esp; кроме того, адресация через esp экономит на прологе push ebp/mov ebp,esp, но теряет по байту на каждом обращении к переменным.
    Сделаем мир лучше!
  • CleverMouse wrote:IgorA, неверно. Нет никакой локальной копии всей библиотеки для конкретного приложения.
    Странно, мне Марио раньше сказал совсем другое, вот цитата из моего ЛС:
    Только сейчас заметил, то что ты сделал в SVN r. 1489.
    Я не знаю сам ли ты додумался или кто подсказал столь гениальное решение, но ты в курсе что записывая в область памяти библиотеки ты автоматом создаешь дублирующую копию всей библиотеки Box_Lib в памяти приложения вызвавшего Lib_Init?

    Программа перестает пользоваться спроецированной копией библиотеки и следовательно каждая программа будет потреблять лишнюю память в размере 60 Кб (если не ошибаюсь). С одной стороны немного, но с другой это нехорошая тенденция.

    Изменяемые данные должны храниться только в области специально предназначенной для работы - work area, обычно так ее называют. Она не является частью библиотеки и на нее передается указатель через стек. Твои изменения сломали этот подход.
  • Я не знаю, откуда Марио это взял. В действительности там постраничный copy-on-write: viewtopic.php?p=29192#p29192
    Сделаем мир лучше!
  • За идею с локальными переменными спасибо, в некоторых случаях подойдёт. Хотя глобальные всё равно надо. Хотя я использовал их как в обычной проге. Запустилось и сбоев никаких. Только лишь хотелось как-то поэкономней с размером библиотеки. Затраты опер. памяти пока особо не волнует.
    Чем больше сыра, тем больше в нём дыр. Чем больше дыр, тем меньше в нём собственно сыра. Значит, чем больше сыра, тем меньше сыра!
  • И ещё вопрос))) Надо чтобы во время работы окна MsgBox основное приложение останавливалось и ждало результата. Хотел всё основать на проверке первого байта в структуре сообщения на 0, но оказалось, что при закрытии бокса(я про крестик, разумеется) там так и остаётся ноль. И функцию на крестик нельзя приделать(не понимаю, зачем так сделано) Можно ли всё-таки обойтись библиотекой или свою мини-версию делать?
    И ещё) Когда выделяешь память, то она забита нулями или как получится?
    И ещё)). Вин функции сохраняют регистры, поэтому приходится делать тоже самое. Я делаю это при помощи pushad/popad. Но когда функция должна вернуть значение приходится как-то сохранять значение. Пока я это делал так:
    mov [var],eax
    popad
    mov eax,[var]
    Теперь, конечно, сделаю var локальным, но вообще как такое обычно делают? Нырял в исходники ядра, что бы посмотреть на сам код int40h, но пока ни разу до шёл)))
    Чем больше сыра, тем больше в нём дыр. Чем больше дыр, тем меньше в нём собственно сыра. Значит, чем больше сыра, тем меньше сыра!
  • GerdtR wrote:И функцию на крестик нельзя приделать(не понимаю, зачем так сделано) Можно ли всё-таки обойтись библиотекой или свою мини-версию делать?
    Чтобы сделать функцию на крестик нужно дорабатывать код самой msgbox. Это не было сделано потому что такое никто не просил сделать. На форуме есть тема посвященная бибилотеке msgbox :
    viewtopic.php?f=45&t=1241
    С нее можно скачать исходные коды бибилиотеки, чтобы доработать ее. Вот только на svn исходных кодов нет, там сразу файл msgbox.obj идет.
    GerdtR wrote:Когда выделяешь память, то она забита нулями или как получится?
    В виндовсе в большинстве случаев да, но может быть и мусор. Как в Колибри не знаю, наверное также.
    GerdtR wrote:Вин функции сохраняют регистры, поэтому приходится делать тоже самое. Я делаю это при помощи pushad/popad.
    Вин функции возвращают значение через регистр eax, потому скорее всего в них делается push/pop для всех изменяемых регистров кроме eax.
    Есть еще один способ возвращения значения, через стек. Но этот способ сложноват, потому что нужно правильно вычислить место в стеке где будет возвращаемое значение.
  • IgorA wrote: Вин функции возвращают значение через регистр eax, потому скорее всего в них делается push/pop для всех изменяемых регистров кроме eax.
    По соглашениям stdcall и cdecl функция может менять eax, ecx, edx, об их сохранности должен заботиться вызывающий код. Пруф
  • Code: Select all

    push ebx ecx edx esi ;registers saved
    ;...
    pop esi edx ecx ebx ;registers restored
  • GerdtR wrote:И ещё) Когда выделяешь память, то она забита нулями или как получится?
    Зависит от того, что значит "выделять память". Функции ядра типа 68.12 обнуляют память при выделении. Но они оперируют целыми страницами, и если нужно выделять мелкие куски типа нескольких десятков байт, получается излишний расход памяти. В подобных случаях нужно использовать какой-нибудь user-mode менеджер, выделяющий, условно говоря, одну страницу из системы, какую-то часть этой страницы для поддержки собственной информации, остальное нарезающий кусками по запросу; user-mode менеджеры, как правило, ничего не гарантируют - новый кусок вполне может содержать данные, оставшиеся от ранее выделенного и освобождённого куска.
    GerdtR wrote:И ещё)). Вин функции сохраняют регистры, поэтому приходится делать тоже самое. Я делаю это при помощи pushad/popad. Но когда функция должна вернуть значение приходится как-то сохранять значение. Пока я это делал так:
    mov [var],eax
    popad
    mov eax,[var]
    Теперь, конечно, сделаю var локальным, но вообще как такое обычно делают? Нырял в исходники ядра, что бы посмотреть на сам код int40h, но пока ни разу до шёл)))
    pushad/popad относительно медленные, хотя и короткие. Лучше сохранять и восстанавливать только те регистры, которые нужно восстановить - например, только ebx, esi, edi. Именно в такой постановке можно написать

    Code: Select all

    mov [esp+1Ch],eax
    popad
    
    Сделаем мир лучше!
  • Who is online

    Users browsing this forum: No registered users and 32 guests