Асамблейна мовна квітка


21

Напишіть найкоротший можливий мовний збірник .

Використовуйте будь-який ISA, який ви хочете, якщо він не має print-quineінструкції або аналогічного. Приклади включають x86, MIPS, SPARC, MMIX, IBM BAL, MIX, VAX, JVM, ARM тощо.

Ви можете зв’язатись зі стандартною _printfфункцією бібліотеки C (або еквівалентом Java для байт-коду JVM) для вводу / виводу.

Довжина буде оцінюватися як за кількістю інструкцій, так і за розміром сегмента даних. Рішення повинні містити щонайменше дві інструкції.

Квіне повинен друкувати код складання , а не зібраний код машини.


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

На жаль, Жасмін не допускає стільки приємних хитрощів, скільки ilasmдозволяє Microsoft . Але JVM має всього шість різних 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коротше bipushабо iconst_*.
  • 2011-02-07 02:30 (952) - Хто каже, що мені потрібно успадкувати від java.lang.Object? Інші назви класів настільки коротші :-)

4

газ для x86 Linux (89 байт, сім інструкцій)

Технічно це обман.

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) Хоча приємна реалізація. Ви можете включити джерело збірки un-db'd, щоб інші глядачі отримали прямий вигляд.
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}

Один рядок, в кінці немає розриву рядка.

Відформатована та коментована перша версія (хоча це вже не квітина) - навряд чи я сильно відхиляюся від загальної концепції:

.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[]локальна змінна; Я можу зробити все це на стеці безпосередньо. Приємно.

Здається, ви видалили об’єкт [] з неформатованої версії, але не відформатованої ...
Aurel Bílý

@Aurel: Дійсно, як зазначалося, відформатований - це найперша версія. Ідея все одно та сама, тому я її більше не оновлюю.
Joey

2

газ для x86 Linux, 184 176 байт

.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Необов’язково, якщо ваша ОС вже 32-розрядна.)

Відредаговано, щоб додати: Якщо ми змінимо правила, щоб дозволити putsвикликати замість printfцього, це можна зробити у 182 174 байтах:

.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 / put, ви насправді залежите від стандартного C prolog / epilog, який прямо не дозволений. І IMHO не мав бути таким; але я отримав головну відповідь: очевидно, я упереджений :-)
JB

Ну, можна стверджувати, що використання C prolog / epilog неявно дозволено через згадування про використання printf (). Функції libc не завжди поводяться надійно, якщо обходити C prolog / epilog. Насправді у моїй системі ваша версія не працює, якщо я передаю висновок у файл, оскільки stdout видається лише в коді C epilog. (Якби ми замість цього використовували write (), який є лише обгорткою навколо системного виклику, він би працював у будь-якому випадку.)
хлібопекарня

Зараз це вже досить давно, але я, мабуть, пригадую, що дозволено функціонувати на С, тоді ще для мене було несподіванкою: це зробило проблему нечистою. ОП вже давно не існує; зараз буде важко вимагати роз'яснень.
JB

Зауважимо, що ABI дозволяє printfвгамувати свої аргументи на стек. З технічної точки зору це не безпечно callзнову та очікувати тих же аргументів, але це працює на практиці, оскільки gcc / clang ніколи не використовує слоти арґусів як місця для подряпин, AFAIK.
Пітер Кордес

Крім того , в цілому це не безпечно викликати printfз _start(наприклад , в статичному довічним), так що це хороший аргумент для написання mainзамість _start. Ця відповідь пояснює різні способи зв’язку libc зі статичними або динамічними бінарними файлами. (У динамічному бінарному файлі Linux, динамічний лінкер буде виконувати функції ініціалізатора glibc, тому ви можете використовувати printfз _startточки входу, але це не так у cygwin IIRC.)
Пітер Кордес,

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 , по-справжньому гольф.


0

x86-64, Система V AMD64 ABI, ГАЗМ: 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якщо вам не байдуже стан виходу вашої програми. Він як і раніше друкує себе, навіть якщо виходить із ненульовим статусом. Ви також можете використовувати pushзамість pushq. Насправді, чому ви взагалі робите стековий кадр? Відкиньте push rbp/ mov rsp, rbpі leave. Ви також можете використовувати короткі назви міток. .Csє 3 символи, коли 1 буде добре.
Пітер Кордес

Після цього, .att_syntax noprefixймовірно, більше не платить за себе. .intel_syntax noprefixдозволив би вам скинути і ці шість $префіксів. але, мабуть, все-таки не варто. (Ви можете використовувати lea ecx,.Csзамість синтаксису Intel mov ecx,offset .Cs)
Пітер Кордес,

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.