Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

использование с++

360
15 ноября 2007 года
P*t*
474 / / 15.02.2007
Хочу написать загрузчик, который грузится с дискеты, грузит с той-же дискеты программу на С/С++, и запускает её.

Есть несколько вопросов по этому поводу:
1) в каком формате компилировать сишную программу
2) как найти точку входа в неё
3) как из программы на С вызвать ассемблерную функцию
4) как из программы на С запустить прерывание

Помогите, пожалуйста.
245
15 ноября 2007 года
~ArchimeD~
1.4K / / 24.07.2006
угу, недаром видно в "отдохнем" про атаку чайников тему открыли, ой недаром... ХАЦУ ПРАГРАММУ. а почитать доки или предыдущие темы - пусть всякие олени читают. постараюсь все-таки ответить коротко

0) RTFM в больших количествах в любое время суток до и после еды
1) компилируй в каком хочешь - хоть PE, хоть ELF, хоть сырой бинарник. и бутсектор пиши для загрузки определенного формата.
2) сначала загрузить. потом уже по загруженному адресу передавать управление. естественно, все ещё зависит от выбранного формата. проще всего с сырым бинарником
3) зависит от компилятора. обычно нечто вроде asm("функция");
4) из вставленного кода на ассемблере

С++ не советую тут брать - С больше подходит.

З.Ы. прочитав то, что я тут понаписал, идешь читать документацию, если что-то непонятно. и не спешишь писать "А ШТО ТАКОИ ... ???"
360
15 ноября 2007 года
P*t*
474 / / 15.02.2007
Все вопросы остались как были.


Цитата: ~ArchimeD~

1) компилируй в каком хочешь - хоть PE, хоть ELF, хоть сырой бинарник. и бутсектор пиши для загрузки определенного формата.



Что надо сказать компилятору (допустим gcc), чтобы он сделал сырой бинарник?

Цитата: ~ArchimeD~

2) сначала загрузить. потом уже по загруженному адресу передавать управление. естественно, все ещё зависит от выбранного формата.
проще всего с сырым бинарником


И где у него точка входа? Первой командой?

Цитата: ~ArchimeD~

3) зависит от компилятора. обычно нечто вроде asm("функция");


Я имел ввиду, что где-то в памяти есть прога на ассемблере и я знаю её адрес. Как в таком случае запустить её из С?

Цитата: ~ArchimeD~

С++ не советую тут брать - С больше подходит.


Ну пусть будет С

245
15 ноября 2007 года
~ArchimeD~
1.4K / / 24.07.2006
Цитата: P*t*

Что надо сказать компилятору (допустим gcc), чтобы он сделал сырой бинарник?


слушай, те про RTFM намек не ясен? man gcc трудно почитать?
я сырой бинарник делаю:

 
Код:
gcc -ffreestanding
ld --oformat binary


Цитата: P*t*

И где у него точка входа? Первой командой?


читай внимательно - все зависит от выбранного формата. берешь, читаешь. у сырого обычно первой командой. или логика хромает?

Цитата: P*t*

Я имел ввиду, что где-то в памяти есть прога на ассемблере и я знаю её адрес. Как в таком случае запустить её из С?



во первых, пиши определеннее, в памяти нет загруженых программ на ассемблере, есть только исполняемый код. без разницы, на чем написанный.

во-вторых, учим основы Си - указатели на функцию:

 
Код:
void (*start)(void)=адрес;
start();
360
17 ноября 2007 года
P*t*
474 / / 15.02.2007
Цитата: ~ArchimeD~

я сырой бинарник делаю:
 
Код:
gcc -ffreestanding
ld --oformat binary



При попытке так откомпилировать

 
Код:
int main() {}

вылезает нечто на пять килобайт.

сомневаюсь, что это то что нужно.
245
18 ноября 2007 года
~ArchimeD~
1.4K / / 24.07.2006
Цитата: P*t*

вылезает нечто на пять килобайт.



вообще неплохо сказать, что пишут, хотя я кажется понял в чем соль:
эт кажется я забыл флаг приписать

 
Код:
gcc -ffreestanding -c
ld --oformat binary


gcc:
-ffreestanding - запрет использования станд. библиотек
-c - выдать объектный файл, а не бинарник (!)

ld:
--oformat binary - скомпоновать сырой бинарник

ели не получится, приведи команды, которыми ты это все собираешь полностью и приведи результат их выполнения.
360
18 ноября 2007 года
P*t*
474 / / 15.02.2007
cPart.c
 
Код:
int main() {
    asmfunc();
}


asmPart.s
 
Код:
.globl asmfunc
asmfunc:
    movb $0, %bh
    movb $'s', %al
    movw $10, %cx
    movb $0xa, %ah
    int $0x10
ret


Код:
# gcc -o cPart.o -ffreestanding -c cPart.c
# gcc -o asmPart.o -ffreestanding -c asmPart.s
# ld -o prog --oformat binary cPart.o asmpart.o
ld: warning: cannot find entry symbol _start; defaulting to 08048000
# ls -gG
итого 48
-rw-rw-r--  1 481 Ноя 18 19:14 asmpart.o
-rw-rw-r--  1 481 Ноя 18 19:21 asmPart.o
-rw-rw-r--  1 100 Ноя 18 19:19 asmPart.s
-rw-rw-r--  1  27 Ноя 18 18:42 cPart.c
-rw-rw-r--  1 784 Ноя 18 19:21 cPart.o
-rwxrwxr-x  1  49 Ноя 18 19:22 prog


Загружаю prog по адресу 0x2000:0x0000,
и по нему же передаю управление : call 0x2000:0x0000

По идее программа должна вывести "ssssssssss" в текущей позиции курсора, но не делает этого.

Кроме того она не возвращает управление вызвавшей программе.
245
18 ноября 2007 года
~ArchimeD~
1.4K / / 24.07.2006
прицепи такую фиговину (это для pm, под rm сам переделаешь) - это будет startup.S:
Код:
#include "startup.h"

.text

.globl  start, _start
start:
_start:
jmp     multiboot_entry
.align  4

multiboot_entry:
pushl   $0
popf

xor %eax, %eax
xor %ebx, %ebx
xor %edx, %edx
xor %ecx, %ecx

movb  $0x10, %al //сюда свой селектор
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss

movl $STACK_ADDR, %esp
call    EXT_C(main)
loop:   hlt
    jmp     loop


startup.h:
 
Код:
#if !defined( startup_h )
#define startup_h

#ifdef HAVE_ASM_USCORE
# define EXT_C(sym)                     _ ## sym
#else
# define EXT_C(sym)                     sym
#endif

#endif


( вообще, как я говорил, ман рулит. почитай man multiboot )

компиляешь все это дело так:
 
Код:
# gcc -ffreestanding -c startup.S cPart.c asmPart.s
# ld -o prog --oformat binary startup.o cPart.o asmpart.o

Ещё проблема - собирается по умолчанию 32-битный код, насчет 16 битного - кури мануал
360
21 ноября 2007 года
P*t*
474 / / 15.02.2007
Добавил в начало команду .code16
Теперь работает.

Зачем нужен код, который ты написал, не понимаю:
ну очищает он регистры - какой от этого смысл?

Осталась одна проблема:
что делать, если вместо бесконечного цикла
loop: hlt
jmp loop
после выполнения программы надо вернуть управление обратно в загрузчик?
"ret" вроде бы ассемблируется как возврат после ближнего перехода. В этом случае он не работает.
245
21 ноября 2007 года
~ArchimeD~
1.4K / / 24.07.2006
Цитата: P*t*

Зачем нужен код, который ты написал, не понимаю:
ну очищает он регистры - какой от этого смысл?



вообще он нужен для перехода на функцию main, ибо до нее обычно лежат строковые данные.

насчет ret посмотрю.

360
21 ноября 2007 года
P*t*
474 / / 15.02.2007
Спасибо :) Всё понятно.
P.S Про ret я сам нашёл - надо lret использовать.
360
22 ноября 2007 года
P*t*
474 / / 15.02.2007
Нет, опять не работает :( : всё было здорово, пока я не попробовал передать в функцию параметер.

cPart.c
 
Код:
asm(".code16");
int main() {
  writeNumber(143);
  nextLine();
}


asmPart.s (и здесь же startup)
Код:
.code16
.globl _start
_start:
    call main
lret

.globl nextLine
nextLine:
    ... (переводит курсор на следущую строчку)
ret

.globl writeNumber
writeNumber:
    movl 4(%esp), %ebx
        ...  Этот код выводит на экран число,
        ...  которое находится в %bx.
        ...  Он совершенно точно работает правильно.
ret


По идее этот код должен вывести на экран "143", но выводит "0" :(

Может быть я неправильно извлекаю параметер из стека?
245
22 ноября 2007 года
~ArchimeD~
1.4K / / 24.07.2006
 
Код:
movl 4(%esp), %ebx


может я и ошибаюсь, но кажись сначала идет адрес возврата, потом уже параметр. поэтому если у тебя код 16-битный, сначала в стеке будет 2 байта адреса возврата. непонятно только, как будет интерпретироваться параметр. я бы посоветовал попробовать попробовать 6 байт

 
Код:
movl 6(%esp), %ebx


З.Ы., а как таки в 16-битном коде ты юзаешь 32-битные регистры? если действительно проходит, то если не получится
 
Код:
movl 6(%esp), %ebx

попробуй уж и
 
Код:
movl 8(%esp), %ebx
360
22 ноября 2007 года
P*t*
474 / / 15.02.2007
А, понятно.
Я считал что адрес возврата - 4 байта, а он 2.
Вот так заработало:
movl 2(%esp), %ebx (а не 6)

32-битные регистры почему-то всё-таки работают
(gcc, кстати, независимо от ".code16" использует 32-битные)

Теперь попробовал сделать более сложный вариант:
 
Код:
asm(".code16");

int main() {
    for (int a=0;a<2;a++) {
        writeNumber(a);
        nextLine();
    }
}


gcc возмущается -
cCode.c: In function ‘main’:
cCode.c:4: error: ‘for’ loop initial declaration used outside C99 mode
не понимаю что это значит

вот так компилируется, но не работает:
 
Код:
asm(".code16");

int main() {
        int a;
    for (a=0;a<2;a++) {
        writeNumber(a);
        nextLine();
    }
}


выводит
0
0
0
0
0
(и.т.д на весь экран)
245
23 ноября 2007 года
~ArchimeD~
1.4K / / 24.07.2006
как-то странно, почему
 
Код:
movl 2(%esp), %ebx (а не 6)
работает... ведь
 
Код:
[параметр][адрес возврата] | вершина
  ~4 байта       2 байта


Цитата:
(gcc, кстати, независимо от ".code16" использует 32-битные)


в реальном режме 32-битных регистров просто не должно быть...

-----------------------

Цитата:
cCode.c:4: error: ‘for’ loop initial declaration used outside C99 mode


эт он ругаеццо на объявление переменной внутри цикла, не по сишному стандарту это

попробуй a объявить с типом char или short

360
23 ноября 2007 года
P*t*
474 / / 15.02.2007
Цитата: ~ArchimeD~

как-то странно, почему
 
Код:
movl 2(%esp), %ebx (а не 6)
работает... ведь
 
Код:
[параметр][адрес возврата] | вершина
  ~4 байта       2 байта


Ну почему странно?
стек будет выглядеть так:
[адрес возврата] [параметер]
xxxxxxxx xxxxxxxx 000 000 000 143
^
esp сюда.

тогда esp+2 указывает на первый байт параметра, что от него и требуется.

Цитата: ~ArchimeD~

в реальном режме 32-битных регистров просто не должно быть...


Может тогда из-за этого и не работает... (хотя врядли).
А запретить gcc использовать 32-битные регистры я не могу...


Цитата: ~ArchimeD~

эт он ругаеццо на объявление переменной внутри цикла, не по сишному стандарту это

попробуй a объявить с типом char или short


Тот же результат.

А когда я выношу объявление за пределы цикла компилируется, но не работат: зацикливается и выводит много нулей.

245
23 ноября 2007 года
~ArchimeD~
1.4K / / 24.07.2006
Цитата: P*t*
Ну почему странно?
стек будет выглядеть так:
[адрес возврата] [параметер]
xxxxxxxx xxxxxxxx 000 000 000 143
^
esp сюда.


блин, это я дундук, с недосыпу не туда вершину стека мысленно прилепил :o прошу прощения

Цитата: P*t*

А когда я выношу объявление за пределы цикла компилируется, но не работат: зацикливается и выводит много нулей.


таки что-то со стеком косо, попробуй объявить глобально (за пределами main)

можешь ещё выдать команду

 
Код:
gcc -S cCode.c

выдаст тебе ассемблерный листинг, посмотри, как в нем будут локальные переменные обрабатываться.
360
23 ноября 2007 года
P*t*
474 / / 15.02.2007
Цитата:

таки что-то со стеком косо, попробуй объявить глобально (за пределами main)


пробовал - не работает

gcc -S пробовал сделать - вроде там всё правильно, единственное, что плохо - он использует исключительно 32-битные регистры

1.9K
23 ноября 2007 года
disasm
232 / / 06.02.2006
Всё-таки лучше по-моему сделать перед запуском функции main переход в PM, по крайней мере тогда не надо будет извращаться с 16-битным стеком и 32-битными переменными..
Либо найти способ (или компилатор) для компиляции Си в 16-битный код, но по-моему gcc этого делать не умеет
360
08 февраля 2008 года
P*t*
474 / / 15.02.2007
прошло несколько месяцев, и я вроде бы освоил переход в защищённый режим.
Появилась новая проблема:

gcc при компиляции делит всё на несколько секций, и в каждой из них адреса отсчитываются от начала этой секции.
ld похоже просто помещает эти секции одну за другой в бинарнике.

когда я из boot-sectora это дело запускаю, нужно настроить ds на начало секции данных. Непонятно как это сделать - кто его знает, на какой адрес эти данные попали... кроме того этот адрес нужно знать ещё до компиляции...

я вижу два пути решения проблемы:
1) пытаться сделать, чтобы при компиляции всё пихалось в одну секцию
2) сделать, чтобы ld поместил секцию данных по заданному адресу в бинарнике.

наверное и то и другое можно сделать указав какую нибудь опцию ld,
но сколько я не смотрел man ничего подходящего не нашёл.

Посоветуйте что нибудь.
360
10 февраля 2008 года
P*t*
474 / / 15.02.2007
Ну что, неужели никто не знает?
Или я неудачно вопрос задал?
260
10 февраля 2008 года
Ramon
1.1K / / 16.08.2003
Везде все есть, просто кто то не хочет искать, типа разжуйте и положите мне в ротик, RTFM.
360
10 февраля 2008 года
P*t*
474 / / 15.02.2007
хотя бы скажи где искать - я смотрел man gcc и man ld. Ничего подходящего не нашёл.
google тоже не помогла...
260
10 февраля 2008 года
Ramon
1.1K / / 16.08.2003
http://gcc.gnu.org/
http://www.gnu.org/software/binutils/

А там есть разделы "Documentation"

Очень сложно найти, практически невозможно, не так ли?
391
11 февраля 2008 года
Archie
562 / / 03.02.2005
Почитай про linker scripts. Вот тебе пример для затравки: http://www.osdever.net/bkerndev/Docs/basickernel.htm
360
12 февраля 2008 года
P*t*
474 / / 15.02.2007
Спасибо. Это именно то, что нужно.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог