2016-06-03 16 views
1

Wenn ich versuche, und das Programm zusammenstellen, erhalte ich ein paar der folgenden Fehlermeldungen:Junk `(0,1,1)‘ nach der Expression

[email protected]:~/test$ as -gstabs test.s -o test.o && ld test.o -o a.out && rm test.o && ./a.out 
test.s: Assembler messages: 
test.s:19: Error: junk `(0,0,1)' after expression 
test.s:20: Error: junk `(0,1,1)' after expression 
test.s:21: Error: junk `(0,2,1)' after expression 
test.s:22: Error: junk `(0,3,1)' after expression 

Kann jemand bitte sagen Sie mir, was genau ich bin falsch machen, dass mein Programm nicht läuft? Offensichtlich hat das etwas damit zu tun, wie ich auf die Array-Elemente zugreifen kann, von denen jedes ein Byte lang ist. Hier ist das Programm selbst:

/****************************************************************************** 
*                   * 
* This program prints the string "foo" on the console.      * 
*                   * 
******************************************************************************/ 

.section .data 
    array: .byte 0x00, 0x00, 0x00, 0x00 # An array of four bytes 
    size: .int 4      # The size of the array 


.section .text 
.globl _start 
_start: 
    movb $0x66, %ah # 66 is the hexadecimal value for 'f' 
    movb $0x6F, %al # 6F is the hexadecimal value for 'o' 
    movb $0x6F, %bh # 6F is the hexadecimal value for 'o' 
    movb $0x0A, %bl # A is the hexadecimal value for '\n' 
    movb %ah, array(0, 0, 1) 
    movb %al, array(0, 1, 1) 
    movb %bh, array(0, 2, 1) 
    movb %bl, array(0, 3, 1) 

    # print 
    movl $4, %eax  # 4 is the number for the write system call 
    movl $1, %ebx  # The file descriptor to write to (1 - STDOUT) 
    movl $array, %ecx # The starting address of the string to print 
    movl size, %edx  # The number of bytes to print 
    int $0x80   # Wake up the kernel to run the write system call 

    # exit 
    movl $1, %eax  # 1 is the number for the exit system call 
    movl $0, %ebx  # Exit status code (echo $?) 
    int $0x80   # Wake up the kernel to run the exit system call 

/* 

Compile and run: 

as -gstabs test.s -o test.o && \ 
ld test.o -o a.out && \ 
rm test.o && \ 
./a.out 

*/ 
+0

Ich würde vorschlagen, Ihre handschriftliche Asm-Quelle in einem '.S', nicht einem' .s' zu halten. 'gcc -S test.c' wird ohne zu fragen" test.s "clobber, aber nichts verwendet standardmäßig' .S' als Ausgabedateierweiterung. Alle asm-Quelldateien von glibc sind zum Beispiel '.S'. Sie können auch leicht mit 'gcc -m32 -nostdlib test.S' kompilieren. –

+0

Ihr Laptop läuft hoffentlich nicht mit 32-Bit-Linux, Sie benötigen also "-m32", um 32-Bit-Code auszuführen. Dieser Code könnte tatsächlich im 64bit-Modus funktionieren, da der "int 0x80" ABI noch verfügbar ist, aber sobald Sie '% esp' anstelle von'% rsp' ändern, sind Sie geschraubt. Siehe [diese Antwort zur Erstellung eines 32-Bit-Codes auf einem 64-Bit-System] (http://stackoverflow.com/questions/36861903/assembling-32-bit-binaries-on-a-64-bit-system-gnu-toolchain/36901649 # 36901649) und andere Links im [x86-Tag-Wiki] (http://stackoverflow.com/tags/x86/info) –

Antwort

1

Es gibt keine asm Syntax für mehrdimensionale Arrays, wenn Sie es sich mit Makros bauen. Oder vielleicht kommen Sie dazu, indem Sie unbenutzte Register durch 0 in (base, index, scale) Syntax ersetzen.

Was Sie tun können, ist ein expression mit einem label, um Offsets davon zu erhalten, wie movb $constant, array + 4.

Der Blick auf Compiler-Ausgabe ist oft ein guter Weg, um zu lernen, wie man Dinge in asm macht, von Syntax-Grundlagen zu cleveren Optimierungstricks. Auf der Godbolt compiler explorer:

#include <string.h> 
char arr[100]; // uninitialized global array 
void copy_string(){ memcpy(&arr[4], "foo\n", 4); } 

    // -O3 -fverbose-asm output: 
    movl $175075174, arr+4  #, MEM[(void *)&arr + 4B] 
    ret 

    .bss 
    .align 32 
arr: 
    .zero 100 

So ist arr+4 die Syntax. Wir könnten movl $const, arr+4(%eax) schreiben, um etwas wie den C-Ausdruck array[4 + i] zu tun. Eine vollständige Liste der x86-Adressierungsmodi finden Sie unter this answer (hauptsächlich NASM/MASM-Syntax, aber was wirklich wichtig ist, ist, was im Maschinencode codiert werden kann.) Siehe auch das Tag-Wiki .


Beachten Sie auch, wie gcc puts uninitialized arrays in the .bss (statt .data oder .rodata). Das bedeutet, dass in Ihrer ausführbaren Datei keine Nullbytes enthalten sind. Statt mit .bss in den Abschnitt zu wechseln, können Sie auch .comm array 100 an einer beliebigen Stelle verwenden, um array zu deklarieren und 100 Bytes dafür im bss zu reservieren. Es ist wahrscheinlich weniger verwirrend nur .bss


zu verwenden, die unmittelbare Konstante natürlich ist 0x0a6f6f66, unseren String. gcc hat das memcpy geschickt in einen 4-Byte-Sofortspeicher optimiert, da es keinen Nutzen hat, dass der/die Wert (e) danach noch in einem Register stehen. Denken Sie daran, dass x86 Little-Endian ist, so geht das 0x66 Byte in array+0 und 0x0a geht in array+3. (Gcc saugt bei fusionierenden separaten schmalen Geschäften außer mit memcpy, obwohl, finden Sie in dem Godbolt Link Klirren ist dies besser..)


In NASM Syntax, man kann sogar mit einem „string“ schreibt es als eine Ganzzahlkonstante

mov dword [array+off], `foo\n` ;backquote for C-style \-escapes, unlike '' or "" 

GNU as dies nicht zulässt, es sei denn, etwas, das als ein Hex-Konstante + Kommentar zu lesen ist schwieriger:

movl $('f' | 'o'<<8 | 'o'<<16 | '\n'<<24), array 

GNU as Syntax nicht so freundlich ist für handgeschriebenen asm als NASM/YASM, aber in mancher Hinsicht ist es nett. (%reg und so weiter macht es einfach, zu sehen, was ist ein Registernamen und was nicht.)


Apropos immediates: Ihre size = 4 sollte eine sofortige konstant sein, nicht eine Last.

## size: .int 4 # Don't need this stored in memory anywhere 
.equ size, 4 
... 

movl $array, %ecx # The starting address of the string to print 
movl $size, %edx # The number of bytes to print 

Beachten Sie auch, dass die movl $constant, (%ecx) weniger Bytes nimmt als movl $constant, array zu kodieren, so könnten Sie Code Bytes speichern, indem $array in %ecx früher bekommen und dann ein einfaches Register mit Modus-Adressierung.

2

Das Problem besteht darin, wie Sie auf die Array-Mitglieder beziehen. Verwenden Sie stattdessen:

movb %ah, array + 0 
movb %al, array + 1 
movb %bh, array + 2 
movb %bl, array + 3