The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

форумы  помощь  поиск  регистрация  майллист  вход/выход  слежка  RSS
"Стек и bootloader"
Вариант для распечатки  
Пред. тема | След. тема 
Форум Программирование под UNIX (C/C++)
Изначальное сообщение [ Отслеживать ]

"Стек и bootloader"  +/
Сообщение от kuraga email(ok) on 29-Дек-10, 11:39 
Я создал загрузчик (asm), который загружает ядро (Си) по адресу в памяти. Реальный режим. Проблема со стеком. Если параметры функции, вызываемой в ядре, передаются через регистры, все ок. Но если нет - через стек - например, переменное количество аргументов, все летит. Как инициализировать стек? Куда должны указывать регистры? Спасибо.

Вот kernel.c. В qemu код ничего не выводит, и выводит 'S', если '...' заменить на 'int x'. Отличие в передаче параметров через стек, как видно в ассемблерном коде.


__asm__(".code16gcc\n");
__asm__ ("jmp _start\n");

int extern __attribute__((noinline)) __attribute__((regparm(3))) sprintf(char * buf, const char *fmt, ...)
{
    __asm__ __volatile__ ("int 0x10" : : "a" (0x0E00 | *fmt), "b"(144));
}

void __attribute__((noreturn)) _start()
{
    char buf[128];
    sprintf(buf, "Sasha%d", 123);
    while(1);
}

Нынешняя инициализация регистров:


    mov    ax, SETUP_ADDR>>4    ; SETUP_SEG
    mov    es, ax
    mov    ds, ax
    mov  cs, ax
    mov  ss, ax
    mov    sp, 0x400
    jmp    SETUP_ADDR>>4:0

Компиляция и запуск:


#!/bin/bash
gcc -c -Wall -save-temps -march=i386 -ffreestanding -Wno-main -fno-builtin -masm=intel -O0 -o kernel.o  kernel.c
ld -nostdlib -static -Ttext 0 --oformat binary -o kernel.bin kernel.o

mkdir diskc
mount -t msdos -o loop=/dev/loop3,blocksize=1024 dos.img diskc
rm diskc/BOOTOR
cp kernel.bin diskc/BOOTOR
umount diskc
rmdir diskc

nasm boot.asm -o boot.bsr
dd if=boot.bsr of=dos.img bs=512 count=1 conv=notrunc

qemu -fda dos.img -boot a


Ответить | Правка | Cообщить модератору

Оглавление

Сообщения по теме [Сортировка по времени | RSS]


1. "Стек и bootloader"  +/
Сообщение от guest email(??) on 29-Дек-10, 12:11 
>  mov sp, 0x400

может просто для стека мало 1кб и соответственно при использовании стека происходит затирание кода. Попробуйте поставить sp на конец сегмента.
К сожалению я не помню как он должен быть выравнен) попробуйте например 0xfffc

Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

2. "Стек и bootloader"  +/
Сообщение от kuraga email(ok) on 29-Дек-10, 13:51 
>>  mov sp, 0x400
> может просто для стека мало 1кб и соответственно при использовании стека происходит
> затирание кода. Попробуйте поставить sp на конец сегмента.
> К сожалению я не помню как он должен быть выравнен) попробуйте например
> 0xfffc

Нет. Да и функция жрет 12 байт... Посмотрите, пожалуйста, я не ем, не сплю, не могу, когда что-то стоит из-за маленького незнания!

Вот полные исходники: http://zalil.ru/30246211

А вот ассемблер ядра:


    .file    "kernel1.c"
    .intel_syntax noprefix
#APP
    .code16gcc

    jmp _start

#NO_APP
    .text
.globl sprintf
    .type    sprintf, @function
sprintf:
    push    ebp
    mov    ebp, esp
    push    ebx
    mov    eax, DWORD PTR [ebp+12]
    mov    al, BYTE PTR [eax]
    movsx    eax, al
    or    ah, 14
    mov    edx, 144
    mov    ebx, edx
#APP
# 6 "kernel1.c" 1
    int 0x10
# 0 "" 2
#NO_APP
    pop    ebx
    leave
    ret
    .size    sprintf, .-sprintf
    .section    .rodata
.LC0:
    .string    "Sasha%d"
    .text
.globl _start
    .type    _start, @function
_start:
    push    ebp
    mov    ebp, esp
    add    esp, -128
    push    123
    push    OFFSET FLAT:.LC0
    lea    eax, [ebp-128]
    push    eax
    call    sprintf
    add    esp, 12
.L4:
    jmp    .L4
    .size    _start, .-_start
    .ident    "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
    .section    .note.GNU-stack,"",@progbits


Ответить | Правка | ^ к родителю #1 | Наверх | Cообщить модератору

3. "Стек и bootloader"  +/
Сообщение от guest email(??) on 29-Дек-10, 14:09 
>[оверквотинг удален]
>  lea eax, [ebp-128]
>  push eax
>  call sprintf
>  add esp, 12
> .L4:
>  jmp .L4
>  .size _start, .-_start
>  .ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
>  .section .note.GNU-stack,"",@progbits
>

Ответить | Правка | ^ к родителю #2 | Наверх | Cообщить модератору

4. "Стек и bootloader"  +/
Сообщение от guest email(??) on 29-Дек-10, 14:16 
Извините нечаянно квотинг отправил.
Почему категорично нет?
На мой взгляд сейчас так:
код смещение 0
...
где-то тут конец кода
стэк смещение 400

код отъедает от несчастного килобайта еще 128байт + сколько-то 32битных push
дальше зовете int10 - стэк стал еще ближе к коду. как оно там устроенно внутре хз. А если
еще и какоенибудь аппаратное прерывание?
Вообщем я бы таки попробовал подвинуть стек в более безопасное место.

Ответить | Правка | ^ к родителю #3 | Наверх | Cообщить модератору

5. "Стек и bootloader"  +/
Сообщение от kuraga email(ok) on 29-Дек-10, 14:27 
>[оверквотинг удален]
> На мой взгляд сейчас так:
> код смещение 0
> ...
> где-то тут конец кода
> стэк смещение 400
> код отъедает от несчастного килобайта еще 128байт + сколько-то 32битных push
> дальше зовете int10 - стэк стал еще ближе к коду. как оно
> там устроенно внутре хз. А если
> еще и какоенибудь аппаратное прерывание?
> Вообщем я бы таки попробовал подвинуть стек в более безопасное место.

"Нет." = "Спасибо. Попробовал, но не помогло." :-) Ставил 0xfffc, 0xf00 и StackSeg (и метка в конце). А так Вы правы, хз почему написал 0x400

Ответить | Правка | ^ к родителю #4 | Наверх | Cообщить модератору

6. "Стек и bootloader"  +/
Сообщение от guest email(??) on 29-Дек-10, 14:57 
> "Нет." = "Спасибо. Попробовал, но не помогло." :-) Ставил 0xfffc, 0xf00 и
> StackSeg (и метка в конце). А так Вы правы, хз почему
> написал 0x400

Тогда кроме как прицепить к quemu gdb и пройтись по шагово ничего посоветовать не могу.

Ответить | Правка | ^ к родителю #5 | Наверх | Cообщить модератору

7. "Стек и bootloader"  +/
Сообщение от kuraga email(ok) on 29-Дек-10, 15:45 
Кажется нарыл. в двоичном файле ядра строка "Sasha%d" строго в конце файла, хотя OFFSET .LC0 по дизассемблеру есть 0. Разве по опции -Ttext оно не должно быть в начале???
Ответить | Правка | ^ к родителю #6 | Наверх | Cообщить модератору

8. "Стек и bootloader"  +/
Сообщение от kuraga email(ok) on 29-Дек-10, 17:14 
Кажется нарыл. в двоичном файле ядра строка "Sasha%d" строго в конце файла, хотя OFFSET .LC0 по дизассемблеру есть 0. Разве по опции -Ttext оно не должно быть в начале???
Ответить | Правка | ^ к родителю #2 | Наверх | Cообщить модератору

10. "Стек и bootloader"  +/
Сообщение от kuraga email(ok) on 29-Дек-10, 22:00 
Я вот че понял: все правильно, он берет смещения переменных от начала какого-то сегмента... Какого? Я просто привык, что мы пишем ASSUME, а GCC такого не пишет... Или это на linux всегда так? Так вот: базирование .LC0 ведь идет по DS? А кто его устанавливает? Сейчас - я, причем абсолютно неправильно!!! А как GCC формирует сегменты? Один сегмент данных или как? Как получить его адрес, и почему он не записывается в DS? И где сегмент стека, какой из указанных опций я его отключил?

Ответьте, пожалуйста, и простите за тупые вопросы! :)

Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

11. "Стек и bootloader"  +/
Сообщение от ImPressed (ok) on 03-Янв-11, 16:36 
> Я вот че понял: все правильно, он берет смещения переменных от начала
> какого-то сегмента... Какого? Я просто привык, что мы пишем ASSUME, а
> GCC такого не пишет... Или это на linux всегда так? Так
> вот: базирование .LC0 ведь идет по DS? А кто его устанавливает?
> Сейчас - я, причем абсолютно неправильно!!! А как GCC формирует сегменты?
> Один сегмент данных или как? Как получить его адрес, и почему
> он не записывается в DS?
И где сегмент стека, какой из
> указанных опций я его отключил?

> Ответьте, пожалуйста, и простите за тупые вопросы! :)

GCC в обыденной жизни сегменты сам не привязывает, т.к полагает что это сделает ОС.

Для того чтобы это делалось, вам надо будет написать ассемблерную процедуру, которая будет вызываться перед  _start() и будет устанавливать SS/DS/ES в нужные значения.
И еще вопрос, вы загружаете ELF-бинарник или plain (а-ля DOS *.COM файл)?

Ответить | Правка | ^ к родителю #10 | Наверх | Cообщить модератору

12. "Стек и bootloader"  +/
Сообщение от kuraga email(ok) on 03-Янв-11, 16:37 
> И еще вопрос, вы загружаете ELF-бинарник или plain (а-ля DOS *.COM файл)?

Второе.


Ответить | Правка | ^ к родителю #11 | Наверх | Cообщить модератору

13. "Стек и bootloader"  +/
Сообщение от ImPressed (ok) on 03-Янв-11, 16:49 
>> И еще вопрос, вы загружаете ELF-бинарник или plain (а-ля DOS *.COM файл)?
> Второе.

Значит тогда так.

После того как ваш бинарь считан с диска, он помещается по адресу 0x7c00:0000 (его туда кладет BIOS после загрузки через INT 19h) и устанавливает CS=DS=ES=SS=0x7c00.
После этого BIOS передает управление на этот адрес.
В boot.ld для меня есть пара подозрительных вещей:

.text AT(0)

Вы хотите чтобы ваш сегмент кода лег в сегмент 0000h(точнее по линейному адресу 00000000h)?
Я правильно вас понял?

Ответить | Правка | ^ к родителю #12 | Наверх | Cообщить модератору

14. "Стек и bootloader"  +/
Сообщение от kuraga email(ok) on 04-Янв-11, 12:10 
>[оверквотинг удален]
> Значит тогда так.
> После того как ваш бинарь считан с диска, он помещается по адресу
> 0x7c00:0000 (его туда кладет BIOS после загрузки через INT 19h) и
> устанавливает CS=DS=ES=SS=0x7c00.
> После этого BIOS передает управление на этот адрес.
> В boot.ld для меня есть пара подозрительных вещей:
> .text AT(0)
> Вы хотите чтобы ваш сегмент кода лег в сегмент 0000h(точнее по линейному
> адресу 00000000h)?
> Я правильно вас понял?

Вот может тут и дыра! Я плохо знаю, что делает эта инструкция. Значение 0 выставил методом тыка...

Как правильно и что это делает (полнеый перечень можно пжл?)

Ответить | Правка | ^ к родителю #13 | Наверх | Cообщить модератору

15. "Стек и bootloader"  +/
Сообщение от ImPressed (ok) on 04-Янв-11, 12:24 
>[оверквотинг удален]
>> устанавливает CS=DS=ES=SS=0x7c00.
>> После этого BIOS передает управление на этот адрес.
>> В boot.ld для меня есть пара подозрительных вещей:
>> .text AT(0)
>> Вы хотите чтобы ваш сегмент кода лег в сегмент 0000h(точнее по линейному
>> адресу 00000000h)?
>> Я правильно вас понял?
> Вот может тут и дыра! Я плохо знаю, что делает эта инструкция.
> Значение 0 выставил методом тыка...
> Как правильно и что это делает (полнеый перечень можно пжл?)

Я вижу, что вы плохо ориентируетесь в архитектуре x86.

В сегменте с линейным адресом 00000000h лежит таблица векторов прерываний ( а точнее их адреса в формате сегмент:смещение). Эта таблица имеет 256 элементов по 4 байта каждый.
Когда вы делаете int xxh, адрес на который CPU при прерывании передаст управление как раз берется оттуда =), а вы туда пишете свой код =)) и как итог вместо передачи управления по определенному адресу, управление передается на случайную область памяти =) и у вас ничего не работает.

Я бы вам посоветовал убрать вообще AT(0).Оно вам там ни к чему.

Это первое замечание.

Замечание номер два:

Если хотите сами вручную задать адрес сегмента стека и положение  указателя стека (регистры SS и SP), запрещайте перед этим все прерывания, т.к это критическая секция, и вызванный обработчик прерывания может записать туда мусор.

т.е делаем так:

cli   # Запрещаем прерывания
mov   sp,...
mov   ax,....
mov   ss,ax
sti   # Разрешаем прерывания

Третье:

Про скрипты LD читаем здесь: http://www.opennet.me/docs/RUS/gnu_ld/

Ответить | Правка | ^ к родителю #14 | Наверх | Cообщить модератору

16. "Стек и bootloader"  +/
Сообщение от kuraga email(ok) on 04-Янв-11, 13:44 
>[оверквотинг удален]
>>> После этого BIOS передает управление на этот адрес.
>>> В boot.ld для меня есть пара подозрительных вещей:
>>> .text AT(0)
>>> Вы хотите чтобы ваш сегмент кода лег в сегмент 0000h(точнее по линейному
>>> адресу 00000000h)?
>>> Я правильно вас понял?
>> Вот может тут и дыра! Я плохо знаю, что делает эта инструкция.
>> Значение 0 выставил методом тыка...
>> Как правильно и что это делает (полнеый перечень можно пжл?)
> Я вижу, что вы плохо ориентируетесь в архитектуре x86.

А я и не говорил, что хорошо. Я студент 2-го курса, да только там нам таких подробностей (пока) не рассказывали. Друзей-программистов у меня нет.

Те замечания, что Вы написали, я знал. Гружу я не в 0, а в 0x0700. Если убрать, не работает вообще. Спасибо огромное, но яснее не стало :)

Ответить | Правка | ^ к родителю #15 | Наверх | Cообщить модератору

17. "Стек и bootloader"  +/
Сообщение от ImPressed (ok) on 04-Янв-11, 14:00 
>[оверквотинг удален]
>>> Вот может тут и дыра! Я плохо знаю, что делает эта инструкция.
>>> Значение 0 выставил методом тыка...
>>> Как правильно и что это делает (полнеый перечень можно пжл?)
>> Я вижу, что вы плохо ориентируетесь в архитектуре x86.
> А я и не говорил, что хорошо. Я студент 2-го курса, да
> только там нам таких подробностей (пока) не рассказывали. Друзей-программистов у меня
> нет.
> Те замечания, что Вы написали, я знал. Гружу я не в 0,
> а в 0x0700. Если убрать, не работает вообще. Спасибо огромное, но
> яснее не стало :)

Грузите с FAT я так понимаю ( boot.asm смахиывает на копию оного из FreeDos =))?

как совет:
Скачайте исходники freedos и посмотрите как это сделано там

Ответить | Правка | ^ к родителю #16 | Наверх | Cообщить модератору

Архив | Удалить

Рекомендовать для помещения в FAQ | Индекс форумов | Темы | Пред. тема | След. тема




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2025 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру