سیستم عامل شمس

پایگاه طراحی سیستم عامل

سیستم عامل شمس

پایگاه طراحی سیستم عامل

فصل سوم : شروع به کار با زبان C

چهارشنبه, ۱۱ آذر ۱۳۹۴، ۰۸:۳۶ ب.ظ

شروع به کار با زبان C

این فصل به شما نشان می دهد که چگونه بجای استفاده از زبان اسمبلی از زبان C بعنوان زبان برنامه نویسی سیستم عاملتان استفاده کنید. زبان اسمبلی ابزار بسیار خوبی برای تعامل با پردازنده است و کنترلی حداکثری برروی تمام ابعاد کد را ارائه می¬دهد. بهرروی حداقل برای مولفان، زبان C زبانی است که برای استفاده بسیار مناسب تر است. در نتیجه، علاقمندیم که از C حداکثر استفاده ممکن را بکنیم و نیز در موارد اضطرار از کدهای اسمبلی در آن استفاده کنیم.

     راه اندازی پشته

یکی از پیش نیازها برای استفاده از C پشته می باشد، بدلیل اینکه تمام برنامه های بزرگ C از پشته استفاده می کنند. راه اندازی پشته سخت تر از این نیست که کاری کنیم تا ثبات esp به انتهای یکی از نواحی حافظه آزاد است (بیاد داشته باشید که پشته در کامپیوترهای x86 به آدرس پائین تر رشد پیدا می کند) که بدرستی تراز شده باشد. (تراز بر 4 بایت از نظر کارایی بهتر پیشنهاد می شود).
ما می توانیم esp را به نقطه ای تصادفی در حافظه اشاره دهیم به این دلیل که تنها چیزی که در حافظه وجود دارد GRUB، BIOS و هسته سیستم عامل و برخی از دستگاه های ورودی خروجی نگاشت شده به حافظه است. این ایده، ایده خوبی نیست – ما نمی دانیم چه میزان از حافظه موجود است یا اینکه esp به ناحیه ای اشاره دارد که توسط برنامه دیگری در حال استفاده کردن از آن است. ایده بهتر این است که از بخش رزرو شده حافظه آماده نشده در بخش bss موجود در فایل ELF هسته استفاده کنیم. بهتره که بجای استفاده از بخش داده به منظور کاهش حجم فایل اجرایی هسته از بخش bss استفاده کنیم. از آنجایی که GRUB قالب ELF را می فهمد، GRUB می تواند هرمیزان حافظه رزرو شده در بخش bss را در زمان بارگذاری سیستم عامل اختصاص دهد.
شبه دستور resb در NASM را می تواند برای استفاده از تعریف داده های آماده سازی نشده استفاده کرد :
    KERNEL_STACK_SIZE equ 4096                  ; size of stack in bytes

    section .bss
    align 4                                     ; align at 4 bytes
    kernel_stack:                               ; label points to beginning of memory
     resb KERNEL_STACK_SIZE                  ; reserve stack for the kernel
 نیاز نیست که درباره استفاده از حافظه آماده سازی نشده برای پشته نگران باشید، به این خاطر که ممکن نیست بتوانیم (بدون تغذیه دستی اشاره گر)یک محل از پشته را بخوانیم که هنوز در آن نوشته نشده است. یک برنامه (درست) نمی تواند عنصری را که از پشته pop کند که هرگز آن را به پشته push نکرده باشد. در نتیجه، محل های حافظه ی پشته همواره باید قبل از آنکه خوانده شوند، نوشته شوند.
پس اشاره گر پشته باید از طریق اشاره esp به انتهای kernel_stack در حافظه اشاره کنند:
    mov esp, kernel_stack + KERNEL_STACK_SIZE   ; point esp to the start of the
                                                ; stack (end of memory area)

  فراخوانی کدهای C از درون کد اسمبلی

گام بعدی این است که یک تابع C را از درون کد اسمبلی مان فراخوانی کنیم.  قرادادهای بسیار گوناگونی در ارتباط با چگونگی فراخوانی کدهای C از کدهای اسمبلی وجود دارد. این کتاب از قرارداد فراخوانی cdecl استفاده می کند زیرا این قراداد توسط GCC بکار گرفته شده است. قرارداد فراخوانی cdecl می گوید که آرگومان های یک تابع باید از طریق پشته به تابع ارسال شوند (برروی ماشین های x86). آرگومان های تابع باید به ترتیب از راست به چپ به پشته push شوند، به این شکل، شما ابتدا سمت راست ترین آرگومان را به پشته push می کنید. مقدار بازگشتی یک تابع باید در ثبات eax قرار گیرد. کد زیر یک مثال را نشان می دهد :
    /* The C function */
    int sum_of_three(int arg1, int arg2, int arg3)
    {
        return arg1 + arg2 + arg3;
    }
نحوه فراخوانی کد بالا در اسمبلی :
    ; The assembly code
    external sum_of_three   ; the function sum_of_three is defined elsewhere

    push dword 3            ; arg3
    push dword 2            ; arg2
    push dword 1            ; arg1
    call sum_of_three       ; call the function, the result will be in eax

بسته بندی  ساختارها

در سرتاسر این کتاب، شما همواره با "پیکربندی بایت ها" که مجموعه ای از بیت ها به ترتیبی مشخص هستند مواجه خواهید بود. در زیر مثالی با 32 بیت آورده شده :
Bit:     | 31     24 | 23          8 | 7     0 |
Content: | index     | address       | config  |
بجای استفاده از اعداد صحیح بدون علامت (unsigned integer) بسیار بهتر است که برای کنترل چنین پیکربندی هایی از قرارداد "ساختارهای بسته بندی شده" استفاده کنید :
    struct example {
        unsigned char config;   /* bit 0 - 7   */
        unsigned short address; /* bit 8 - 23  */
        unsigned char index;    /* bit 24 - 31 */
    };
وقتی در مثال قبلی از struct استفاده کردیم هیچ تضمینی به ما داده نشد که طول این ساختار دقیقاً 32 بیت باشد – کامپایلر می تواند به دلایل مختلف مقداری فاصله گذاری بین عناصر انجام دهد، بعنوان مثال جهت افزایش سرعت دسترسی به عناصر یا به منظور الزامات سخت افزاری سخت افزار و/یا کامپایلر. وقتی که از یک struct برای نمایش بایت های پیکربندی استفاده کنیم، مهم است که کامپایلر هیچ فاصله گذاری  انجام ندهد زیرا struct به طور اتفاقی به شکل یک مقدار عدد صحیح 32 بیتی توسط سخت افزار رفتار خواهد کرد/ مشخصه packed را می توان به منظور مجبور کردن GCC به عدم فاصله گذاری بکار گرفت :
    struct example {
        unsigned char config;   /* bit 0 - 7   */
        unsigned short address; /* bit 8 - 23  */
        unsigned char index;    /* bit 24 - 31 */
    } __attribute__((packed));
به یاد داشته باشید که ((attribute__((packed__ بخشی از C استاندارد نیست ممکن است در همه ی کامپایلرها کار نکند.

     کامپایل کردن کد C

زمانیکه کد C را برای سیستم عامل کامپایل می کنید، بسیاری از پرچم های GCC لازم است که به دستور کامپایل اضافه شوند. انجام این کار به این دلیل است که کد C نباید حضور کتابخانه های استاندارد فرض کند، به این خاطر که در سیستم عامل ما هیچ کتابخانه استانداردی وجود ندارد. برای اطلاع از پرچم ها، راهنمای (manual) مربوط به GCC را مطالعه کنید.
پرچم های استفاده شده برای کدهای C به شکل زیر هستند :
    -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles
    -nodefaultlibs
مثل همیشه، زمانی که برنامه ای به زبان C می نویسید ما پیشنهاد می کنیم که تمام هشدارها را فعال کنید و با آن ها بمانند خطاها برخورد کنید :
-Wall -Wextra -Werror    
حال شما می¬توانید در فایلی به نام kmain.c تابعی با نام kmain ایجاد کنید که بتوانید از طریق Loader.s آن را فراخوانی کنید. در این لحظه از آموزش احتمالاً kmain به هیچ آرگومانی نیاز نخواهد داشت (امّا در فصول بعدی خواهد داشت).

     ابزارهای ساختن

در این لحظه احتمالاً زمان خوبی برای راه اندازی برخی ابزارهای ساختن برای ساده کردن پروسه کامپایل و آزمایش و اجرای سیستم عامل وجود داشته باشد. سیستم های ساختن فراوانی وجود دارد امّا پیشنهاد می کنیم که از make استفاده کنید. یک makefile ساده برای سیستم عامل می تواند به شکل زیر باشد :
    OBJECTS = loader.o kmain.o
    CC = gcc
    CFLAGS = -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector \
             -nostartfiles -nodefaultlibs -Wall -Wextra -Werror -c
    LDFLAGS = -T link.ld -melf_i386
    AS = nasm
    ASFLAGS = -f elf

    all: kernel.elf

    kernel.elf: $(OBJECTS)
        ld $(LDFLAGS) $(OBJECTS) -o kernel.elf

    os.iso: kernel.elf
        cp kernel.elf iso/boot/kernel.elf
        genisoimage -R                              \
                    -b boot/grub/stage2_eltorito    \
                    -no-emul-boot                   \
                    -boot-load-size 4               \
                    -A os                           \
                    -input-charset utf8             \
                    -quiet                          \
                    -boot-info-table                \
                    -o os.iso                       \
                    iso

    run: os.iso
        bochs -f bochsrc.txt -q

    %.o: %.c
        $(CC) $(CFLAGS)  $< -o $@

    %.o: %.s
        $(AS) $(ASFLAGS) $< -o $@

    clean:
        rm -rf *.o kernel.elf os.iso
محتوای شاخه کاری شما در حال حاضر باید به شکل زیر در آمده باشد :
    .
    |-- bochsrc.txt
    |-- iso
    |   |-- boot
    |     |-- grub
    |       |-- menu.lst
    |       |-- stage2_eltorito
    |-- kmain.c
    |-- loader.s
    |-- Makefile
حالا شما باید قادر باشید که که سیستم عامل را با یک دستور ساده make run اجرا کنید، این دستور هسته را کامپایل می کند و آن را برروی مقلّد bochs بوت می کند (به همانگونه که در فایل makefile بالا تعریف شده است).

     مطالعات بعدی

کتاب زبان برنامه نویسی C نوشته ریچی و کرنیگان، ویراست دوّم، منبعی گرانبها برای یادگیری تمام جنبه های زبان C است.

نظرات  (۲)

  • cheap car insurance
  • Hola:Estaba buscando algún plugin para insertar fotografías en mi blog, desde Picasa. Al aprecer, tu encontraste uno, pero no colocas ningún link ni enlace que permita ubciar y descargar el plugin…Pucha, ojalá que actualices y pueda ubicar con mayor facilidad este plugin, ya que aún mejor, entrega el efecto lightbox, que es espectacular.SaludosAndrecom
  • http://kreditsuche.pw/privat-autokredit.html
  • By the way, you forgot one of the biggest hot mic gafs of all when Jesse Jackson called New York City Heimytown, it cost him a chance to run for president.
    ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
    شما میتوانید از این تگهای html استفاده کنید:
    <b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
    تجدید کد امنیتی