C, 866 783 바이트
내 코드는 32 비트 ELF 실행 파일을 출력하므로 모든 사람의 설정에서 작동한다고 약속 할 수 없습니다. 실행 파일이 내 컴퓨터에서 segfaulting을 중지하도록하려면 약간의 조정이 필요했습니다.
이것을 실행하려는 사람은 :
$ uname --all
Linux 4.4.0-24-generic #43-Ubuntu SMP Wed Jun 8 19:27:37 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
Brainfuck 프로그램은 stdin에서 읽고 컴파일 된 ELF는 stdout에 작성됩니다.
#define P *(t++)
#define C case
#define B break
char a[30000],b[65535],f,*t=b;*c[100];**d=c;main(g){P=188;t+=4;while((f=getchar())!=-1)switch(f){C'>':P=68;B;C'<':P=76;B;C'+':P=254;P=4;P=36;B;C'-':P=254;P=12;P=36;B;C'.':P=187;t+=4;P=137;P=225;P=186;P=1;t+=3;P=184;P=4;t+=3;P=205;P=128;B;C',':P=187;P=1;t+=3;P=137;P=225;P=186;P=1;t+=3;P=184;P=3;t+=3;P=205;P=128;B;C'[':P=138;P=4;P=36;P=133;P=192;P=15;P=132;t+=4;*d=(int*)t-1;d++;B;C']':P=138;P=4;P=36;P=133;P=192;P=15;P=133;t+=4;d--;g=((char*)(*d+1))-t;*((int*)t-1)=g;**d=-g;B;}P=184;P=1;t+=3;P=187;t+=4;P=205;P=128;*(int*)(b+1)=0x8048054+t-b;long long z[]={282579962709375,0,4295163906,223472812116,0,4297064500,4294967296,577727389698621440,36412867248128,30064779550,140720308490240};write(1,&z,84);write(1,b,t-b);write(1,a,30000);}
언 골프
ungolfed 코드 버전에서 무슨 일이 일어나고 있는지 더 잘 알 수 있습니다. 골프 코드의 끝에있는 문자 배열은 ungolfed 코드의 ELF 및 프로그램 헤더 인코딩입니다. 이 코드는 또한 각 Brainfuck 명령이 바이트 코드로 변환되는 방법을 보여줍니다.
#include <linux/elf.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#define MAX_BIN_LEN 65535
#define MAX_JUMPS 100
unsigned int org = 0x08048000;
unsigned char move_right[] = {0x44}; /*inc esp */
unsigned char move_left[] = {0x4c}; /*dec esp */
unsigned char inc_cell[] = {0xfe,0x04,0x24}; /*inc [esp] */
unsigned char dec_cell[] = {0xfe,0x0c,0x24}; /*dec [esp] */
unsigned char read_char[] = {0xbb,0x00,0x00,0x00,0x00, /*mov ebx, 0 */
0x89,0xe1, /*mov ecx, esp */
0xba,0x01,0x00,0x00,0x00, /*mov edx, 1 */
0xb8,0x03,0x00,0x00,0x00, /*mov eax, 3 */
0xcd,0x80}; /*int 0x80 */
unsigned char print_char[] = {0xbb,0x01,0x00,0x00,0x00, /*mov ebx, 1 */
0x89,0xe1, /*mov ecx, esp */
0xba,0x01,0x00,0x00,0x00, /*mov edx, 1 */
0xb8,0x04,0x00,0x00,0x00, /*mov eax, 4 */
0xcd,0x80}; /*int 0x80 */
unsigned char loop_start[] = {0x8a,0x04,0x24, /*mov eax, [esp] */
0x85,0xc0, /*test eax, eax */
0x0f,0x84,0x00,0x00,0x00,0x00}; /*je int32_t */
unsigned char loop_end[] = {0x8a,0x04,0x24, /*mov eax, [esp] */
0x85,0xc0, /*test eax, eax */
0x0f,0x85,0x00,0x00,0x00,0x00}; /*jne int32_t */
unsigned char call_exit[] = {0xb8,0x01,0x00,0x00,0x00, /*mov eax, 1 */
0xbb,0x00,0x00,0x00,0x00, /*mov ebx, 0 */
0xcd,0x80}; /*int 0x80 */
unsigned char prelude[] = {0xbc,0x00,0x00,0x00,0x00}; /*mov esp, int32_t*/
unsigned char tape[100];
int main(){
unsigned char text[MAX_BIN_LEN];
unsigned char *txt_ptr = text;
int32_t *loop_jmps[MAX_JUMPS];
int32_t **loop_jmps_ptr = loop_jmps;
Elf32_Off entry;
entry = org + sizeof(Elf32_Ehdr) + 1 * sizeof(Elf32_Phdr);
memcpy(txt_ptr,prelude,sizeof(prelude));
txt_ptr += sizeof(prelude);
char input;
while((input = getchar()) != -1){
switch(input){
case '>':
memcpy(txt_ptr,move_right,sizeof(move_right));
txt_ptr += sizeof(move_right);
break;
case '<':
memcpy(txt_ptr,move_left,sizeof(move_left));
txt_ptr += sizeof(move_left);
break;
case '+':
memcpy(txt_ptr,inc_cell,sizeof(inc_cell));
txt_ptr += sizeof(inc_cell);
break;
case '-':
memcpy(txt_ptr,dec_cell,sizeof(dec_cell));
txt_ptr += sizeof(dec_cell);
break;
case '.':
memcpy(txt_ptr,print_char,sizeof(print_char));
txt_ptr += sizeof(print_char);
break;
case ',':
memcpy(txt_ptr,read_char,sizeof(read_char));
txt_ptr += sizeof(read_char);
break;
case '[':
memcpy(txt_ptr,loop_start,sizeof(loop_start));
txt_ptr += sizeof(loop_start);
*loop_jmps_ptr = (int32_t*) txt_ptr - 1;
loop_jmps_ptr++;
break;
case ']':
memcpy(txt_ptr,loop_end,sizeof(loop_end));
txt_ptr += sizeof(loop_end);
loop_jmps_ptr--;
int32_t offset = ((unsigned char*) (*loop_jmps_ptr + 1)) - txt_ptr;
*((int32_t*)txt_ptr - 1) = offset;
**loop_jmps_ptr = -offset;
break;
}
}
memcpy(txt_ptr,call_exit,sizeof(call_exit));
txt_ptr += sizeof(call_exit);
*(int32_t*)(text + 1) = entry + (txt_ptr - text);
Elf32_Ehdr ehdr = {
{0x7F,'E','L','F',ELFCLASS32,ELFDATA2LSB,EV_CURRENT,0,0,0,0,0,0,0,0,0},
ET_EXEC,
EM_386,
EV_CURRENT,
entry,
sizeof(Elf32_Ehdr),
0,
0,
sizeof(Elf32_Ehdr),
sizeof(Elf32_Phdr),
1,
0,
0,
SHN_UNDEF,
};
Elf32_Phdr phdr = {
PT_LOAD,
0,
org,
org,
sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) + (txt_ptr - text),
sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) + (txt_ptr - text),
PF_R | PF_X | PF_W,
0x1000,
};
int out = open("a.out",O_CREAT|O_TRUNC|O_WRONLY,S_IRWXU);
write(out,&ehdr,sizeof(Elf32_Ehdr));
write(out,&phdr,sizeof(Elf32_Phdr));
write(out,text,txt_ptr-text);
write(out,tape,sizeof(tape));
close(out);
}
자기 수정 BrainFuck
바이트를 절약하기 위해 내 컴파일러의 테이프는 .bss
섹션이나 그와 비슷한 멋진 부분에 할당되지 않습니다 . 대신, 테이프는 Brainfuck 프로그램의 컴파일 된 바이트 코드 바로 뒤에 작성된 30,000 개의 널 바이트입니다. 이것을 알고 내 컴파일러가 생성하는 바이트 코드를 알고 있으면 런타임에 바이트 코드를 생성하거나 수정할 수 있습니다. 이 '기능'에 대한 간단한 설명은 자체 종료 값을 설정하는 Brainfuck 프로그램입니다.
<<<<<<+
프로그램은 종료 코드가 정상적으로 0이 설정되는 지점까지 테이프의 왼쪽 가장자리에서 바이트 코드로 이동합니다.이 바이트를 증가 시키면 프로그램이 종료 될 때 종료 코드가 0 대신 1로 설정됩니다. 지속성으로 Brainfuck에서 시스템 레벨 프로그래밍을 수행하는 데 사용할 수 있습니다.