어셈블리 언어 Quine


20

가능한 가장 짧은 어셈블리 언어 quine을 작성하십시오 .

print-quine지시 사항이나 이와 동등한 내용 이 없으면 원하는 ISA를 사용하십시오 . 예를 들어 x86, MIPS, SPARC, MMIX, IBM BAL, MIX, VAX, JVM, ARM 등이 있습니다.

_printfI / O 에 대한 C 표준 라이브러리 기능 (또는 JVM 바이트 코드와 동등한 Java)에 링크 할 수 있습니다 .

길이는 명령 수와 데이터 세그먼트의 크기 모두에서 판단됩니다. 솔루션에는 최소한 두 가지 지침이 포함되어야합니다.

quine은 조립 된 기계 코드가 아닌 조립 코드를 인쇄해야 합니다.


3
오 와우, 이것은 강인한 것 같습니다
익명의 겁쟁이

답변:


20

x86 Linux, AT & T 구문 : 244

push $10
push $34
push $s
push $34
push $37
push $37
push $s
call printf
mov $0,%ebx
mov $1,%eax
int $128
s:.ascii "push $10
push $34
push $s
push $34
push $37
push $37
push $s
call printf
mov $0,%cebx
mov $1,%ceax
int $128
s:.ascii %c%s%c%c"

(나는이 그것을 컴파일 : gcc -nostartfiles -lc quine.S -o quine)


그것은 지금 우울합니다 :-(
Joey

1
나는 보통 "직무를위한 올바른 도구"라고 말하지만 여기서 다시는 기분이 좋지 않습니다 : D
JB

;-)
Joey

5

JVM 바이트 코드 어셈블리 ( Jasmin을 통해 ) – 952 960 990

.class public Q
.super java/io/File
.method public static main([Ljava/lang/String;)V
.limit stack 9
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc ".class public Q%n.super java/io/File%n.method public static main([Ljava/lang/String;)V%n.limit stack 9%ngetstatic java/lang/System/out Ljava/io/PrintStream;%nldc %c%s%c%nldc 3%nanewarray java/lang/Object%ndup%ndup%nldc 0%nldc 34%ninvokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;%ndup_x2%naastore%nldc 2%nswap%naastore%ndup2%nswap%nldc 1%nswap%naastore%ninvokevirtual java/io/PrintStream/printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;%npop%nreturn%n.end method"
ldc 3
anewarray java/lang/Object
dup
dup
ldc 0
ldc 34
invokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;
dup_x2
aastore
ldc 2
swap
aastore
dup2
swap
ldc 1
swap
aastore
invokevirtual java/io/PrintStream/printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
pop
return
.end method

안타깝게도 Jasmin은 Microsoft가 허용하는만큼 많은 유용한 트릭을 허용하지 않습니다 ilasm. 그러나 JVM에는 모든 종류의 재미있는 작업을 수행 하는 총 6 가지 dup명령이 있습니다. 스택에서 항목 순서를 바꾸는 것은 .NET이 지원하지 않는 것입니다.

어쨌든, 두 개의 항목 중 가장 짧은 코드에 대한 심각한 경쟁자가 아니라고 생각하지만 훨씬 짧게 만드는 것은 어렵다고 생각합니다. 따라서 완전성을 위해 :-)

스택에있는 정보에 대한 주석이 달린 버전 :

.class public Q
.super java/io/File
.method public static main([Ljava/lang/String;)V
.limit stack 9
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc ".class public Q%n.super java/io/File%n.method public static main([Ljava/lang/String;)V%n.limit stack 9%ngetstatic java/lang/System/out Ljava/io/PrintStream;%nldc %c%s%c%nldc 3%nanewarray java/lang/Object%ndup%ndup%nldc 0%nldc 34%ninvokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;%ndup_x2%naastore%nldc 2%nswap%naastore%ndup2%nswap%nldc 1%nswap%naastore%ninvokevirtual java/io/PrintStream/printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;%npop%nreturn%n.end method"
ldc 3       ; stack; System.out, string, 3
anewarray java/lang/Object    ; stack: System.out, string, Object[3]
dup
dup    ; stack: System.out, string, array, array, array
ldc 0  ; stack: System.out, string, array, array, array, 0
ldc 34   ; stack: System.out, string, array, array, array, 0, 34
invokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;
dup_x2   ; stack: System.out, string, array, array, 34, array, 0, 34
aastore  ; stack: System.out, string, array, array, 34
ldc 2    ; stack: System.out, string, array, array, 34, 2
swap     ; stack: System.out, string, array, array, 2, 34
aastore  ; stack: System.out, string, array
dup2     ; stack: System.out, string, array, string, array
swap     ; stack: System.out, string, array, array, string
ldc 1    ; stack: System.out, string, array, array, string, 1
swap     ; stack: System.out, string, array, array, 1, string
aastore  ; stack: System.out, string, array
invokevirtual java/io/PrintStream/printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
pop
return
.end method

역사:

  • 2011-02-07 02:09 (990) – 첫 번째 작업 버전.
  • 2011-02-07 02:11 (960) – 또는 ldc보다 짧습니다 .bipushiconst_*
  • 2011-02-07 02:30 (952) – java.lang.Object에서 상속해야한다고 누가 말합니까? 다른 클래스 이름은 너무 짧습니다 :-)

4

x86 Linux 용 가스 (89 바이트, 7 개 명령어)

엄밀히 말하면, 이것은 부정 행위입니다.

mov $4,%al
mov $1,%bl
mov $b,%ecx
mov $89,%dl
int $128
mov %bl,%al
int $128
b:.incbin"a"

이름이 지정된 파일에 저장 a하고 다음 명령으로 어셈블하여 이름이 지정된 실행 파일을 작성하십시오 a.out.

as -o a.o ; ld a.o

지시문 .incbin은 현재 위치에서 파일을 그대로 포함합니다. 이것을 사용하여 소스 코드 자체를 포함 시키면 멋진 일이 벌어집니다.


3

Windows .COM 형식 : 307 자

A86을 사용하는 어셈블리는 51 바이트입니다. DOS Int21 AH = 9 기능 이외의 외부 라이브러리가 필요하지 않습니다 (문자열을 stdout에 기록).

db 185
db  51
db   0
db 190
db   0
db   1
db 191
db  47
db   1
db 172
db 178
db  10
db 199
db   6
db  45
db   1
db  32
db  32
db 180
db   0
db 246
db 242
db 128
db 196
db  48
db 136
db  37
db  79
db  10
db 192
db 117
db 242
db 180
db   9
db 186
db  42
db   1
db 205
db  33
db 226
db 221
db 195
db 100
db  98
db  32
db  32
db  51
db  49
db  10
db  13
db  36

357 바이트를 계산하는 것이 두렵습니다. (그러나 프로그램은 실제로 408을 출력합니다) 멋진 구현입니다. 다른 뷰어가 직접 볼 수 있도록 비 DB 어셈블리 소스를 포함 할 수 있습니다.
JB

@JB : CR \ NL을 포함하지 않았습니다. 지금 살펴보면 데이터를 단일 db 행에 넣었어야합니다. 그것은 더 작아 질 것입니다.
Skizz

3

NASM, 223 바이트

%define a "%define "
%define b "db "
%define c "%deftok "
%define d "a, 97, 32, 34, a, 34, 10, a, 98, 32, 34, b, 34, 10, a, 99, 32, 34, c, 34, 10, a, 100, 32, 34, d, 34, 10, c, 101, 32, 100, 10, b, 101, 10"
%deftok e d
db e

받아 들인 대답을 이겼다!


2

.NET CIL - 623 669 691 723 727

.assembly H{}.method void M(){.entrypoint.locals init(string)ldstr".assembly H{0}{1}.method void M(){0}.entrypoint.locals init(string)ldstr{2}{3}{2}stloc 0ldloc 0ldc.i4 4newarr object dup dup dup dup ldc.i4 0ldstr{2}{0}{2}stelem.ref ldc.i4 1ldstr{2}{1}{2}stelem.ref ldc.i4 2ldc.i4 34box char stelem.ref ldc.i4 3ldloc 0stelem.ref call void[mscorlib]System.Console::Write(string,object[])ret{1}"stloc 0ldloc 0ldc.i4 4newarr object dup dup dup dup ldc.i4 0ldstr"{"stelem.ref ldc.i4 1ldstr"}"stelem.ref ldc.i4 2ldc.i4 34box char stelem.ref ldc.i4 3ldloc 0stelem.ref call void[mscorlib]System.Console::Write(string,object[])ret}

한 줄, 끝에 줄 바꿈이 없습니다.

첫 번째 버전을 형식화하고 주석을 달았습니다 (더 이상 quine은 아니지만). 일반적인 개념에서 많이 벗어나지 않을 것입니다.

.assembly H{}
.method void M() {
  .entrypoint
  .locals init (
    string,
    object[]
  )
  // the string
  ldstr".assembly H{0}{1}.method void M(){0}.entrypoint.locals init(string,object[])ldstr{2}{3}{2}stloc.0 ldloc.0 ldc.i4.4 newarr object stloc.1 ldloc.1 ldc.i4.0 ldstr{2}{0}{2} stelem.ref ldloc.1 ldc.i4.1 ldstr{2}{1}{2} stelem.ref ldloc.1 ldc.i4.2 ldc.i4 34 box char stelem.ref ldloc.1 ldc.i4.3 ldloc.0 stelem.ref ldloc.1 call void[mscorlib]System.Console::Write(string,object[])ret{1}"
  stloc.0   // store in first local var
  ldloc.0   // load again. Going to be the first argument to Console::Write
  ldc.i4.4 newarr object stloc.1   // create new array and store in local var
  ldloc.1 ldc.i4.0 ldstr"{" stelem.ref   // we need a literal brace
  ldloc.1 ldc.i4.1 ldstr"}" stelem.ref   // closing, too
  ldloc.1 ldc.i4.2 ldc.i4 34 box char stelem.ref   // double quote
  ldloc.1 ldc.i4.3 ldloc.0 stelem.ref   // our format string from before
  ldloc.1 // load array
  call void[mscorlib]System.Console::Write(string,object[]) // output
  ret
}

연혁 :

  • 2011-02-06 16:48 (727) – 첫 번째 작업 버전.
  • 2011-02-06 17:14 (723) – 문자열 리터럴 뒤에 공백이 필요하지 않습니다.
  • 2011-02-06 17:21 (691) – 매번 dup쓰는 것보다 짧습니다 ldloc.1.
  • 2011-02-06 17시 24분 (669)는 - 나는 후 공간이 필요하지 않습니다 어떤 문자 그대로의 사물이 원하는 ldloc.1대로 쓸 수있는 ldloc 1마지막 토큰 리터럴 확인합니다. 결과 바이트 코드는 더 클 수 있지만 어셈블러 코드에 관한 것이므로 걱정하지 않아도됩니다. :-)
  • 2011-02-06 17:34 (623) – object[]지역 변수로는 필요하지 않습니다 . 스택에서 직접 모든 것을 할 수 있습니다. 좋은.

포맷되지 않은 버전에서 object []를 제거했지만 포맷 된 버전은 제거하지 않은 것 같습니다.
Aurel Bílý

@Aurel : 실제로 언급 한 바와 같이, 포맷 된 것은 가장 첫 번째 버전입니다. 아이디어는 여전히 동일하므로 다시 업데이트하지 않습니다.
Joey

2

x86 Linux 용 가스, 184176 바이트

.globl main
main:movw $34,B+87
push $B
call printf
call printf
pop B
ret
.data
B:.ascii".globl main
main:movw $34,B+87
push $B
call printf
call printf
pop B
ret
.data
B:.ascii"

로 빌드하십시오 gcc -m32 -o a.out quine.S. (그만큼-m32 OS가 이미 32 비트 인 경우 옵션입니다.)

추가하기 위해 편집 :puts 대신 호출 할 수 있도록 규칙을 수정하면 182 174 바이트 printf로 수행 할 수 있습니다 .

.globl main
main:movw $34,B+86
push $B+1
call puts
call puts
pop B
ret
.data
B:.ascii"
.globl main
main:movw $34,B+86
push $B+1
call puts
call puts
pop B
ret
.data
B:.ascii"

(이것은 이전과 달리 종료 줄 바꿈이 있습니다.)


나는 부족에 감사합니다. 그러나 나는 printf / puts 외에도 실제로 표준 C 프롤로그 / epilog에 의존한다는 사실에 속아 있다고 생각합니다. 그리고 IMHO는 의도되지 않았습니다. 그러나 나는 최고의 대답을 얻었습니다 : 분명히 나는 ​​편견입니다 :-)
JB

음, printf () 사용에 대한 언급 때문에 C 프롤로그 / 에필로그 사용이 암시 적으로 허용된다고 주장 할 수 있습니다. C 프롤로그 / 에필로그를 무시하면 libc 함수가 항상 안정적으로 동작하지는 않습니다. 실제로 내 시스템에서는 stdout이 C epilog 코드에서만 플러시되기 때문에 출력을 파일로 파이프하면 버전이 작동하지 않습니다. (대신 syscall을 감싸는 래퍼 인 write ()를 사용했다면 어느 쪽이든 작동했을 것이다.)
breadbox

꽤 오랜 시간이 지났지 만 C 함수가 허용 된 것은 놀랍다는 것을 기억합니다. 문제가 불완전하게 들리게했습니다. OP는 오랫동안 주변에 없었습니다. 지금 설명을 요청하기가 어려울 것입니다.
JB

ABI를 사용 printf하면 스택에서 인수를 클로버 할 수 있습니다 . 기술적으로 안전하지 않고 call동일한 인수를 기대하지만 gcc / clang은 args 슬롯을 스크래치 공간 AFAIK로 사용하지 않기 때문에 실제로 작동합니다.
Peter Cordes 2016 년

또한 일반적으로 (예 : 정적 이진에서) 호출 printf하는 것이 안전하지 않으므로 _starta main대신 을 작성하는 것이 좋습니다 _start. 이 답변 은 정적 또는 동적 바이너리에서 libc를 연결하는 다양한 방법을 설명합니다. (Linux 동적 바이너리에서 동적 링커는 glibc의 이니셜 라이저 기능을 실행하므로 진입 점 printf에서 사용할 수 _start있지만 cygwin IIRC에서는 그렇지 않습니다.)
Peter Cordes

1

부팅 가능한 ASM, 660 바이트

[bits 16]
mov ax,07C0h
mov ds,ax 
mov ah,0
mov al,03h 
int 10h
mov si,code
call p 
jmp $
p:mov ah,0Eh
r:lodsb
cmp al,0
je d
cmp bx,0x42
jne s
c:int 10h
jmp r
s: cmp al,94 
je re
cmp al,63
je q
jmp c
q:mov al,34
jmp c
re:push si
mov bx,0x42
mov si,code
call p 
mov bx,0
pop si
jmp p 
d:ret
code:db "[bits 16]\mov ax,07C0h\mov ds,ax\mov ah,0\mov al,03h\int 10h\mov si,code\call p\jmp $\p:mov ah,0Eh\r:lodsb\cmp al,0\je d\cmp bx,0x42\jne s\c:int 10h\jmp r\s:cmp al,94\je re\cmp al,63\je q\jmp c\q:mov al,34\jmp c\re:push si\mov bx,0x42\mov si,code\call p\mov bx,0\pop si\jmp p\\d:ret\\code:db ?^?\times 510-($-$$) db 0\dw 0xAA55"
times 510-($-$$) db 0
dw 0xAA55

원래에 의해 jdiez17 , 진정으로 당신에 의해 golfed.


0

x86-64, 시스템 V AMD64 ABI, GASM : 432

.att_syntax noprefix
.globl main
main:
pushq rbp
movq rsp, rbp
mov $.Cs, rdi
mov $0xa, rsi
mov $0x22, edx
mov $.Cs, ecx
mov $0x22, r8d
mov $0xa, r9d
xor eax, eax
call printf
xor eax, eax
leave
ret
.Cs: .string ".att_syntax noprefix
.globl main
main:
pushq rbp
movq rsp, rbp
mov $.Cs, rdi
mov $0xa, rsi
mov $0x22, edx
mov $.Cs, ecx
mov $0x22, r8d
mov $0xa, r9d
xor eax, eax
call printf
xor eax, eax
leave
ret%c.Cs: .string %c%s%c%c"

1
피연산자 사이에 쉼표 뒤에 공백이 필요하지 않습니다. xor eax,eax프로그램의 종료 상태에 신경 쓰지 않아도 전혀 필요 하지 않습니다. 0이 아닌 상태로 종료 되더라도 여전히 자체 인쇄됩니다. push대신에 사용할 수도 있습니다 pushq. 실제로 왜 스택 프레임을 만드는가? push rbp/ mov rsp, rbp및을 삭제하십시오 leave. 더 짧은 레이블 이름을 사용할 수도 있습니다. .Cs1이면 괜찮을 때 3 자입니다.
Peter Cordes

그 후, .att_syntax noprefix아마 더 이상 스스로를 지불하지 않을 것입니다. .intel_syntax noprefix이 6 개의 $접두사도 삭제할 수 있습니다 . 그러나 여전히 가치가 없습니다. ( lea ecx,.CsIntel-syntax 대신 사용할 수 있습니다 mov ecx,offset .Cs)
Peter Cordes

0

TAL

push puts
push \100
push {push puts
push \100
push {@}
dup
strmap
invokeStk 2}
dup
strmap
invokeStk 2

이를 실행하려면 ::tcl::unsuppoted::assemble코드를 인수로 호출하십시오.
Tcl 8.6 만 해당.


3
바이트 수를 포함해야합니다.
MD XF

0

80x86 TASM, 561 바이트

MODEL TINY
.CODE
.STARTUP
DB 177
DB 076
DB 186
DB 044
DB 001
DB 172
DB 180
DB 036
DB 179
DB 004
DB 191
DB 080
DB 001
DB 079
DB 136
DB 037
DB 212
DB 010
DB 004
DB 048
DB 134
DB 196
DB 075
DB 117
DB 244
DB 180
DB 009
DB 205
DB 033
DB 178
DB 071
DB 226
DB 228
DB 178
DB 038
DB 205
DB 033
DB 195
DB 013
DB 010
DB 069
DB 078
DB 068
DB 036
DB 077
DB 079
DB 068
DB 069
DB 076
DB 032
DB 084
DB 073
DB 078
DB 089
DB 013
DB 010
DB 046
DB 067
DB 079
DB 068
DB 069
DB 013
DB 010
DB 046
DB 083
DB 084
DB 065
DB 082
DB 084
DB 085
DB 080
DB 013
DB 010
DB 068
DB 066
DB 032
END
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.