বুটলোডার গল্ফ: ব্রেইনফ ***


20

একটি বুটলোডার তৈরি করুন যা প্রদত্ত ব্রেনফাক প্রোগ্রাম কার্যকর করে। এটি , তাই কমপক্ষে বাইটস সহ প্রোগ্রামটি জয়ী হয়। বুটলোডার হওয়ায় প্রোগ্রামের আকারটি সংকলিত কোডে নন-শূন্য বাইটে গণনা করা হয়।

Brainfuck

30000 8-বিট উপচে পড়া ঘর। পয়েন্টার মোড়ানো।

অপারেশন সম্পর্কে কিছু নোট:

  • ইনপুট অবশ্যই এমনভাবে পড়তে হবে যাতে সমস্ত মুদ্রণযোগ্য ASCII অক্ষর সঠিকভাবে সমর্থিত হয়। অন্যান্য কীস্ট্রোকগুলি হয় একটি স্বেচ্ছাচারী চরিত্র sertোকাতে পারে বা কিছুই করতে পারে না।
  • ব্যবহারকারীর ইনপুট পড়তে অবশ্যই অক্ষর বাফার হওয়া উচিত, লাইন বাফার নয়।
  • ব্যবহারকারীর ইনপুট পড়তে অবশ্যই অবশ্যই sertedোকানো অক্ষরটি প্রতিধ্বনিত হবে।
  • আউটপুট অবশ্যই কোড পৃষ্ঠা 437 বা আপনার অন্তর্নির্মিত ভিজিএ অ্যাডাপ্টারের ডিফল্ট কোডপেজ অনুসরণ করবে।

বুট-লোডার

এটি একটি x86 বুটলোডার। একটি বুটলোডার traditional 55 AAতিহ্যগত ক্রম দিয়ে শেষ হয় । আপনার কোডটি ভার্চুয়ালবক্স, কেমু বা অন্যান্য সুপরিচিত x86 এমুলেটরে চালাতে হবে।

ডিস্ক

এক্সিকিউটেবল ব্রেইনফাক আপনার ডিস্কের প্রথম সেক্টর, এমবিআর বিভাগে, সাধারণত আপনার বুটলোডারের ঠিক পরে দ্বিতীয় ডিস্ক সেক্টরে অবস্থিত। অতিরিক্ত কোড (510 বাইটের বেশি কোনও কোড) অন্যান্য ডিস্ক সেক্টরে অবস্থিত হতে পারে। আপনার স্টোরেজ ডিভাইসটি একটি হার্ড ড্রাইভ বা ফ্লপি ডিস্ক হতে হবে।

stdio

অবশ্যই, একটি বুটলোডার অপারেটিং সিস্টেমের আইও সক্ষমতায় অ্যাক্সেস রাখতে পারে না। সুতরাং পাঠ্য মুদ্রণ এবং ব্যবহারকারীর ইনপুট পড়ার পরিবর্তে বিআইওএস ফাংশন ব্যবহৃত হয়।

টেমপ্লেট

শুরু করতে, এখানে নাসমের (ইন্টেল সিনট্যাক্স) সমাবেশে লেখা একটি সাধারণ টেম্পলেট রয়েছে:

[BITS 16]
[ORG 0x7c00]

; first sector:

boot:
    ; initialize segment registers
    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax

    ; initialize stack
    mov sp, 0x7bfe

    ; load brainfuck code into 0x8000
    ; no error checking is used
    mov ah, 2       ; read
    mov al, 1       ; one sector
    mov ch, 0       ; cylinder & 0xff
    mov cl, 2       ; sector | ((cylinder >> 2) & 0xc0)
    mov dh, 0       ; head
                    ; dl is already the drive number
    mov bx, 0x8000  ; read buffer (es:bx)
    int 0x13        ; read sectors


; fill sector
times (0x200 - 2)-($-$$) db 0

; boot signature
db 0x55, 0xaa

; second sector:

db 'brainfuck code here'

times 0x400-($-$$) db 0

এটি সংকলন করা বেশ সহজ:

nasm file.asm -f bin -o boot.raw

এবং এটি চালান। উদাহরণস্বরূপ, কেমু সহ:

qemu-system-i386 -fda boot.raw

সংযোজন সম্পর্কিত তথ্য: ওসডেভ উইকি , উইকিপিডিয়া


21
Input must be redআমি নিশ্চিত যে বেশিরভাগ বুটলোডার স্থানীয়ভাবে রঙ সমর্থন করে না।
মনিকা এর মামলা মোকদ্দমা করুন

4
ছোট বিকাশকারীদের একটি ফ্লপি ডিস্ক কি তা বোঝানো উচিত!
bobbel

1
@ বুবলেল আসুন বুটলোডার দিয়ে শুরু করুন
বুলিন্ট

5
আমি এই শিরোনামটিকে আপত্তিকর বলে মনে করি না, তবে কীভাবে এটি সম্ভব? মেটা অনুসারে , শিরোনামটিতে "ব্রেইনফাক" রাখা অসম্ভব।
DJMcMayhem

আমরা কি 30k এর বেশি সেল ব্যবহার করতে পারি?
ক্যালকুলেটরফলাইন

উত্তর:


13

171 বাইট 1

Wooohoooo! আধ দিন লাগল, কিন্তু মজা লাগল ...

সুতরাং, এটি এখানে। আমি মনে করি এটি চশমা অনুসারে (সেল পয়েন্টারের মোড়ক, ইনপুটটিতে অক্ষরের প্রতিধ্বনি, চর দ্বারা চর পড়া, ইনপুট অক্ষরের প্রতিধ্বনি, ...), এবং এটি আসলে কাজ করে বলে মনে হয় (ভাল, আমি অনেক প্রোগ্রাম চেষ্টা করেছিলাম না) , তবে ভাষার সরলতা দেওয়া, কভারেজটি তেমন খারাপ নয়, আমি মনে করি)।

সীমাবদ্ধতা

একটি গুরুত্বপূর্ণ বিষয়: যদি আপনার ব্রেইনফাক প্রোগ্রামে 8 টি ব্রেইনফাক নির্দেশাবলী বাদে অন্য বর্ণ থাকে বা যদি এটি []ভালভাবে ভারসাম্য না হয় তবে তা আপনার উপর ক্র্যাশ হয়ে যাবে, মওহাহাহাহাহ!

এছাড়াও, ব্রেনফাক প্রোগ্রামটি 512 বাইট (একটি সেক্টর) অতিক্রম করতে পারে না। আপনি যেহেতু "এক্সিকিউটেবল ব্রেইনফাক দ্বিতীয় ডিস্ক সেক্টরে অবস্থিত" বলছেন তাই এটি মেনে চলে ।

শেষ বিবরণ: আমি স্পষ্টভাবে কোষগুলিকে শূন্যে সূচনা করি নি। কিমু আমার জন্য এটি করেছে বলে মনে হচ্ছে, এবং আমি এটির উপর নির্ভর করছি, তবে সত্যিকারের কম্পিউটারে কোনও সত্যিকারের বায়োস এটি করবে কিনা তা আমি জানি না (আরম্ভিকরণে যাই হোক, কিছুটা বাইট আরও বেশি লাগবে)।

কোড

(আপনার টেমপ্লেটের উপর ভিত্তি করে, এবং যাইহোক, এর জন্য ধন্যবাদ, আমি এটি ছাড়া কখনও চেষ্টা করতাম না):

[BITS 16]
[ORG 0x7C00]

%define cellcount 30000 ; you can't actually increase this value much beyond this point...

; first sector:

boot:
    ; initialize segment registers
    xor ax, ax
    mov ss, ax
    mov ds, ax
    mov es, ax
    jmp 0x0000:$+5

    ; initialize stack
    mov sp, 0x7bfe

    ; load brainfuck code into 0x8000
    ; no error checking is used
    mov ah, 2       ; read
    mov al, 1       ; one sector
    mov ch, 0       ; cylinder & 0xff
    mov cl, 2       ; sector | ((cylinder >> 2) & 0xc0)
    mov dh, 0       ; head
                    ; dl is already the drive number
    mov bx, 0x8000  ; read buffer (es:bx)
    int 0x13        ; read sectors

    ; initialize SI (instruction pointer)
    mov si, bx ; 0x8000
    ; initialize DI (data pointer)
    mov bh, 0x82
    mov di, bx ; 0x8200

decode:
    lodsb ; fetch brainfuck instruction character
.theend:
    test al, al ; endless loop on 0x00
    jz .theend
    and ax, 0x0013 ; otherwise, bit shuffling to get opcode id
    shl ax, 4
    shl al, 2
    shr ax, 1
    add ax, getchar ; and compute instruction implementation address
    jmp ax

align 32, db 0

getchar:
    xor ah, ah
    int 0x16
    cmp al, 13
    jne .normal
    mov al, 10 ; "enter" key translated to newline
.normal:
    mov byte [di], al
    push di
    jmp echochar

align 32, db 0

decrementdata:
    dec byte [di]
    jmp decode

align 32, db 0

putchar:
    push di
    mov al, byte [di]
echochar:
    mov ah, 0x0E
    xor bx, bx
    cmp al, 10 ; newline needs additional carriage return
    jne .normal
    mov al, 13
    int 0x10
    mov al, 10
.normal:
    int 0x10
    pop di
    jmp decode

align 32, db 0

incrementdata:
    inc byte [di]
    jmp decode

align 32, db 0

decrementptr:
    dec di
    cmp di, 0x8200 ; pointer wraparound check (really, was that necessary?)
    jge decode
    add di, cellcount
    jmp decode

align 32, db 0

jumpback:
    pop si
    jmp jumpforward

align 32, db 0

incrementptr:
    inc di
    cmp di, 0x8200+cellcount  ; pointer wraparound check
    jl decode
    sub di, cellcount
    jmp decode

align 32, db 0

jumpforward:
    cmp byte [di], 0
    jz .skip
    push si
    jmp decode
.skip:
    xor bx, bx ; bx contains the count of [ ] imbrication
.loop:
    lodsb
    cmp al, '['
    je .inc
    cmp al, ']'
    jne .loop
    test bx, bx
    jz decode
    dec bx
    jmp .loop
.inc:
    inc bx
    jmp .loop

; fill sector
times (0x1FE)-($-$$) db 0

; boot signature
db 0x55, 0xAA

; second sector contains the actual brainfuck program
; currently: "Hello world" followed by a stdin->stdout cat loop

db '++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.,[.,]'

times 0x400-($-$$) db 0

কৌশল ব্যবহার করা হয়েছে

ঠিক আছে, আমি কিছুটা প্রতারণা করেছি। যেহেতু আপনি বলেছেন "বুটলোডার, তাই প্রোগ্রামের আকারটি সংকলিত কোডে নন-শূন্য বাইটে গণনা করা হয়" , তাই আমি আটটি ব্রেইনফাক ওপকোডগুলির প্রয়োগের মধ্যে "গর্ত" দিয়ে কোডটি ছোট করে দিয়েছি। এইভাবে, আমার পরীক্ষার বড় ক্রম, একটি জাম্প টেবিল বা অন্য কোনও কিছুর দরকার নেই: আমি ব্রেইনফাকের নির্দেশটি কার্যকর করতে 32 টি দিয়ে গুণ করে "অপকড আইডি" (0 থেকে 8 পর্যন্ত) ঝাঁপিয়ে পড়েছি (এটি লক্ষ করার মতো বিষয়) এর অর্থ নির্দেশাবলী বাস্তবায়ন 32 বাইটের বেশি নিতে পারে না)।

তদ্ব্যতীত, ব্রেইনফাক প্রোগ্রামের চরিত্রটি আনার জন্য এই "ওপকোড আইডি" পেতে, আমি লক্ষ্য করেছি যে কেবল কিছুটা বদলানো প্রয়োজন। প্রকৃতপক্ষে, যদি আমরা কেবল অপকড চরিত্রের বিট 0, 1 এবং 4 বিবেচনা করি, তবে আমরা 8 টি অনন্য সংমিশ্রণটি শেষ করব:

   X  XX
00101100 0x2C , Accept one byte of input, storing its value in the byte at the pointer.
00101101 0x2D - Decrement (decrease by one) the byte at the pointer.
00101110 0x2E . Output the value of the byte at the pointer.
00101011 0x2B + Increment (increase by one) the byte at the pointer.
00111100 0x3C < Decrement the pointer (to point to the next cell to the left).
01011101 0x5D ] Jump back after the corresp [ if data at pointer is nonzero.
00111110 0x3E > Increment the pointer (to point to the next cell to the right).
01011011 0x5B [ Jump forward after the corresp ] if data at pointer is zero.

এবং, ভাগ্যবান আমার, বাস্তবে এমন একটি অপকোড রয়েছে যার বাস্তবায়নের জন্য 32 বাইটেরও বেশি প্রয়োজন, তবে এটি শেষটি (এগিয়ে যেতে [)) পরে আরও জায়গা থাকায় সবকিছু ঠিক আছে।

অন্যান্য কৌশল: আমি জানি না যে একটি সাধারণ ব্রেইনফাক ইন্টারপ্রেটার কীভাবে কাজ করে তবে জিনিসগুলিকে আরও ছোট করে তোলার জন্য আমি আসলে " পয়েন্টারের ডেটা ননজারো হলে সংশ্লিষ্টের পরে ফিরে যান"] হিসাবে বাস্তবায়ন করি নি । পরিবর্তে, আমি সর্বদা সংশ্লিষ্টটিতে ফিরে যাই এবং, এখান থেকে, আদর্শ প্রয়োগটি পুনরায় প্রয়োগ করি (যা পরে, প্রয়োজনে আবার পিছনে এগিয়ে যায় )। এর জন্য, প্রতিবার আমি হ'ল একটি , আমি অভ্যন্তরীণ নির্দেশাবলী কার্যকর করার আগে স্ট্যাকের উপরের "ব্রেইনফাক নির্দেশ নির্দেশিকা" রাখি এবং যখন আমার মুখোমুখি হয়[[[][], আমি নির্দেশ পয়েন্টারটি পিছনে ফেলেছি। খুব সুন্দর যেন এটি কোনও ফাংশনে কল। অতএব আপনি তাত্ত্বিকভাবে অনেকগুলি মিশ্রিত লুপ তৈরি করে স্ট্যাকটিকে উপচে ফেলতে পারেন, তবে যাইহোক, ব্রেইনফাক কোডটির বর্তমান 512-বাইট সীমাবদ্ধতার সাথে নয়।


১. শূন্য বাইটগুলি সহ যা কোড নিজেই অংশ ছিল, তবে কিছু প্যাডিংয়ের অংশ ছিল না

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.