Forum: Mikrocontroller und Digitale Elektronik Assemblerprogrammierung ARM CORTEX


von Uwe H. (Gast)


Lesenswert?

Schönen guten Tag zusammen!

Seit einigen Wochen arbeite ich mich in die Arm Cortex Architektur ein, 
konkret Atmel SAMD10D14 mit M0+ CPU. In C (Atmel Studio) läuft es ganz 
gut, ich komme voran, diverse Taktfrequenzen laufen "schon". So wollte 
ich mal auch kleine Assemblerprogramme schreiben, um auch mal das Ding 
genau von Innen kennenzulernen, back to the roots, ich liebe Assembler 
trotz seiner Nachteile wie Aufwand und Portabilität. Eine Assembler 
Entwicklungsumgebung scheint es nicht zu geben, Atmel Studio patzt 
genauso wie Eclipse. Bei ersterem habe ich nach Anweisung alle C Files 
rausgeworfen, allerdings bindet der Assembler noch einige Files ein, was 
sich nicht abändern läßt in der Toolchain, da das Parameterfeld für 
arm-none-eabi-gcc grau hinterlegt ist, also nichts geändert werden kann. 
Auch der Assembler mault legale Befehle an wie mov r1,#80 (cannot honor 
width suffix). So nutze ich nun auf Kommandoebene unter Linux die 
Gnu-Arm toolchain:

arm-none-eabi-as -mcpu=cortex-m0plus -mthumb test_arm.s -o test_arm.o
arm-none-eabi-ld -e 0 -Ttext=0x0 -o test_arm.elf test_arm.o
arm-none-eabi-objcopy -O ihex test_arm.elf test_arm.hex

Und hier stoße ich auf ein weiteres Problem. Obwohl ich mit der 
Direktive .org genau angebe, wo die Vektortabelle und der Maschinencode 
platziert werden sollen, wird ab Adresse 0 der Code abgelegt, danach 
folgt die Vektortabelle (umgekehrt wäre richtig). Auch Versuche mit 
Direktiven wie .text und .data bleiben unerhört. Im Quellcode habe ich 
außerdem die Reihenfolge - Vektoren -Assemblerbefehle. Was mache ich 
falsch? Was ist von der GNU Toolchain zu halten, zumal mein Disassembler 
behauptet, aus mov r1, #80 wird ein 32 Bit ARM Befehl movw erzeugt, der 
erst ab dem M3 verstanden wird? Gibt es nicht eine schöne kostenlose 
Entwicklungsumgebung für reine Assemblerprogramme, denn ich habe langsam 
keine Lust mehr auf diese Assembler Odyssee?

Herzlichst,

Uwe

von Til S. (Firma: SEGGER) (til_s)


Lesenswert?

Uwe H. schrieb:
> Gibt es nicht eine schöne kostenlose
> Entwicklungsumgebung für reine Assemblerprogramme,

Ja, nimm einfach SEGGER Embedded Studio. Damit kannst du dir ein Projekt 
für dein Device generieren lassen. Du kannst dann einfach die main.c 
usw. raus schmeißen und fügst deinen Assemblercode in dem Startup Code 
hinzu. Damit startest du mit etwas funktionierendem, was für dich 
einfacher sein sollte.
https://www.segger.com/products/development-tools/embedded-studio/


Das Problem bei dir wird sein, dass du kein Linkerfile hast, welches dem 
Linker sagt, welche Section er wo hinlegen soll, also z.B. die Vektoren 
auf 0x00 und das Programm dahinter.

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

Uwe H. schrieb:

> Und hier stoße ich auf ein weiteres Problem. Obwohl ich mit der
> Direktive .org genau angebe, wo die Vektortabelle und der Maschinencode
> platziert werden sollen, wird ab Adresse 0 der Code abgelegt,

was Du ja hiermit explizit einforderst:

> arm-none-eabi-ld -e 0 -Ttext=0x0 -o test_arm.elf test_arm.o

von Jim M. (turboj)


Lesenswert?

Uwe H. schrieb:
> Obwohl ich mit der
> Direktive .org genau angebe, wo die Vektortabelle und der Maschinencode
> platziert werden sollen, wird ab Adresse 0 der Code abgelegt

Das ist IMO dokumentiertes Verhalten von Gnu LD. Der ist zu dumm um ohne 
ein explizites Linker Skript (und entsprechende Deklarationen im 
Quelltext) Sachen an definierte Addressen zu legen.

Darüber hinaus gibt es AFAIK keine Möglichkeit etwaige Lücken sinnvoll 
zu füllen, d.h. wenn ich was im Code an Addresse 0x1000 haben will kann 
er den restlichen Code in .text nur davor oder dahinter packen.

Für Arm Cortex-M würde ich eher einen C-Compiler empfehlen.

Das hat auch den Hintergrund das es auf den dickeren µCs oft 2,3,4x 
dieselbe Hardware nur an unterschiedlichen Addressen gibt. Das kann ich 
in C relativ leicht abhandeln (Pointer), in Assembler wären das 
irgendwelche Makros.

Uwe H. schrieb:
> Eine Assembler
> Entwicklungsumgebung scheint es nicht zu geben, Atmel Studio patzt
> genauso wie Eclipse.

Hmm, ich habe hier in Eclipse ein paar Assembler Files in den Cortex-M C 
Projekten mit drin, die tun alle ohne Probleme. Allerdings war da IIRC 
auch was manuell anzupassen, was das Parsing und den Indexer anging. Ist 
leider schon zu lange her für Detais.

von Christopher J. (christopher_j23)


Lesenswert?

Til S. schrieb:
> Du kannst dann einfach die main.c usw. raus schmeißen und fügst deinen
> Assemblercode in dem Startup Code hinzu.

Ich kenne eure IDE nicht aber normalerweise ist der Startup-Code von 
Atmel in C geschrieben und nicht in Assembler.

von Uwe H. (Gast)


Lesenswert?

Den Start-up Code wollte ich natürlich  auch in Assembler schreiben, 
also Alles, angefangen von der Vektortabelle bis hin zu den 
Interrupt-/Exceptionroutinen, Initialisierungen, Alles! Ist doch nicht 
schwer und macht Spaß, denn man hat die totale Kontrolle. In C packt man 
dir noch paar Libraries dazu, wo du nicht genau weißt, was die so alles 
machen, was für Nebeneffekte die haben. Klar kann man das mit viel 
Zeitaufwand erforschen, sich durch Macros und Strukturen mit Bitfeldern 
durcharbeiten. Bei sicherheitskritischen Sachen würde ich mir ernsthaft 
überlegen, ob Assembler nicht die transparentere und sichere Alternative 
wäre, denn was die Compiler so an Assemblercode vom Stapel lassen, ist 
meistens schwer verständlich im Gegensatz zum selbst geschriebenen Code!
Bitte nicht falsch verstehen: Ich will hier keinen Religionskrieg 
starten Assembler gegen Hochsprache!!!!

von Peter D. (peda)


Lesenswert?

Du könntest eine *.S Datei erzeugen, zum Build hinzufügen und dann im 
Main aufrufen.

von Johannes S. (Gast)


Lesenswert?

In der GCC Toolchain sind üblicherweise Muster für den Startup Code 
dabei, in .\share\gcc-arm-none-eabi\samples\startup.

von Jim M. (turboj)


Lesenswert?

Christopher J. schrieb:
> Ich kenne eure IDE nicht aber normalerweise ist der Startup-Code von
> Atmel in C geschrieben und nicht in Assembler.

Autsch. Dann sollte man sich den in Assembler von einem anderen 
Hersteller klauen, dank Cortex-M stimmen ja wenigstens die Fault Handler 
bis zum SysTick.

Die restlichen Handler müssten angepasst werden, kann man dann aber aus 
der C-Datei abschreiben.

von Uwe H. (Gast)


Lesenswert?

Hallo Johannes und Jim!

Nicht der Start-up Code ist das Problem, sondern den Assemblercode 
richtig assembliert zu bekommen! Bisher sieht es so aus, daß ich mir 
wohl ein Linkerfile schreiben muss, damit alles an die richtigen 
Adressen gepackt wird. Mal schauen, wie man das macht.....
Gruß

Uwe

von Peter D. (peda)


Lesenswert?

Uwe H. schrieb:
> In C packt man
> dir noch paar Libraries dazu, wo du nicht genau weißt, was die so alles
> machen, was für Nebeneffekte die haben.

Die mache nur wichtige Sachen (RAM nullen, Stack setzen, Takt, PLL 
setzen usw.). Wenn sie Nebeneffekte hätten, dann hätte das bestimmt 
schon jemand bemerkt.

Uwe H. schrieb:
> Bei sicherheitskritischen Sachen würde ich mir ernsthaft
> überlegen, ob Assembler nicht die transparentere und sichere Alternative
> wäre

Bei sicherheitskritischen Sachen würde ich auf keinen Fall den 
Programmierer unnütz von der eigentlichen Aufgabe ablenken, indem ich 
ihm z.B. das Push/Pop-Gedöns aufbürde. Verwaltungs-Sachen kann der 
Compiler viel besser und vor allem fehlerfrei.

von Christopher J. (christopher_j23)


Angehängte Dateien:

Lesenswert?

Uwe H. schrieb:
> Den Start-up Code wollte ich natürlich  auch in Assembler schreiben,
> also Alles, angefangen von der Vektortabelle bis hin zu den
> Interrupt-/Exceptionroutinen, Initialisierungen, Alles!

Ok, ist verstanden. Habe ich selber auch mal gemacht.

Uwe H. schrieb:
> Ist doch nicht
> schwer und macht Spaß, denn man hat die totale Kontrolle.

Dito ;)

Ich hab dir mal ein absolut minimalistisches Blinky (für STM32) 
angehängt, was in 84 Byte läuft (ja, es geht kleiner und nein, das 
Programm ist nicht sinnvoll). Ohne Interrupts, Startup-Code usw. Der 
Startup-Code ist gewissermaßen das Blinky. Das solltest du relativ 
problemlos auf den SAMD10 anpassen können. Die "minimale" Vektortabelle 
ist vorhanden, d.h. initialer SP und PC aber sonst eben nichts. Da 
kannst du noch deine Vektoren einbauen.

Das Makefile ist gewissermaßen auch ein Witz. Kann man innerhalb weniger 
Sekunden auch in eine .sh oder .bat umbauen, deshalb hier der gesamte 
Inhalt:
1
all:
2
  arm-none-eabi-as -mthumb -mcpu=cortex-m3 -o miniblink.o miniblink.S
3
  arm-none-eabi-ld -T miniblink.ld -o miniblink.elf miniblink.o
4
  arm-none-eabi-objcopy -O binary miniblink.elf miniblink.bin
5
  arm-none-eabi-size miniblink.elf

Hier sei noch angemerkt, dass man "normalerweise" weder as zum 
assemblen, noch ld zum linken benutzt. Beides übernimmt in der Regel der 
gcc und zwar mit
1
arm-none-eabi-gcc -x assembler-with-cpp # für den Assembler
2
# und
3
arm-none-eabi-gcc # für den Linker

Dem Linker-Script fehlt quasi der komplette Teil für den RAM, also .data 
und .bss, weil die einfach nicht gebraucht werden, weil eben kein RAM 
genutzt wird. Ist eben minimalistisch aber man kann es ja noch 
erweitern. Da es ebenfalls sehr klein ist, hier der komplette Inhalt:
1
MEMORY
2
{
3
  ROM (rx) : ORIGIN = 0x08002000, LENGTH = 64k
4
  RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
5
}
6
7
_estack = ORIGIN(RAM) + LENGTH(RAM);
8
9
ENTRY(gpioconfig)
10
11
SECTIONS
12
{
13
  .text : {
14
    KEEP(*(.vector_table))
15
    *(.text*)
16
  } >ROM
17
}

Das ENTRY(gpioconfig) kann man sich schenken. Normalerweise steht dort 
ENTRY(reset_handler) oder so ähnlich. Ist jedoch in jedem Fall meines 
Wissens nach überflüssig. _estack ist das Symbol für den initialen 
Stackpointer und zeigt auf das Ende des RAM (was ja ohnehin nicht 
benutzt wird aber sei es drum) und der Rest sagt einfach nur: "pack 
.vector_table vor .text und beides ins ROM".

von Dr. Sommer (Gast)


Lesenswert?

Uwe H. schrieb:
> Atmel Studio patzt
> genauso wie Eclipse.
In eclipse ist das kein Problem, einfach alle .c Dateien löschen und den 
Assembler Code in .S Dateien packen. Die müssen natürlich in der GNU 
Assembler Syntax vorliegen. Wenn du -nostartfiles -nostdlib an den 
Linker übergibst, wird da auch sonst nichts mit reingezogen. Bei z.B. 
den STM32 in den Hersteller-Beispielen der Startup-Code und ISR-Vektor 
sowieso schon in Assembler, und du kannst auch einfach die normalen 
Linker-Scripte übernehmen, die interessiert es nicht ob C oder Assembler 
genutzt wird.

von Til S. (Firma: SEGGER) (til_s)


Angehängte Dateien:

Lesenswert?

Christopher J. schrieb:
> Til S. schrieb:
>> Du kannst dann einfach die main.c usw. raus schmeißen und fügst deinen
>> Assemblercode in dem Startup Code hinzu.
>
> Ich kenne eure IDE nicht aber normalerweise ist der Startup-Code von
> Atmel in C geschrieben und nicht in Assembler.

Ja, kenne ich aber ist in diesem Fall tatsächlich Assembler.

@Uwe
Ich habe dir schnell mal ein Projekt für den SAMD10D14 und Embedded 
Studio zusammen gebaut. In dem Projekt sind keine C Dateien drin sondern 
nur Assemblercode. Du kannst deinen Assemblercode direkt in der 
thumb_crt0.s ergänzen oder dort einen Assemblerfunktion in einem 
separaten Assemblermodul aufrufen. Das Projekt macht gerade nur einfach 
ein while(1) (b .) und ich habe dir einen Kommentar eingefügt, damit du 
weißt, wo du deinen Code einfügen musst.

von Dr. Sommer (Gast)


Lesenswert?

PS: Man braucht auch kein eigenes Makefile schreiben, man kann z.B. die 
Projekt-Templates vom GNU-MCU-Eclipse-Plugin nutzen und eclipse alles 
automatisch assemblisieren/linken lassen. So hat man mehr das Feeling 
einer Entwicklungsumgebung und weniger Handfrickelei.

von Qwerty (Gast)


Lesenswert?

Ich würde Keil µvision verwenden.

Die packs für den SAMD10D14 findet man unter:
http://www.keil.com/dd2/pack/

Darin enthalten sind auch die startup files (startup_SAMD10.s) in 
assembler.

von Markus F. (mfro)


Lesenswert?

Uwe H. schrieb:
> Bisher sieht es so aus, daß ich mir
> wohl ein Linkerfile schreiben muss, damit alles an die richtigen
> Adressen gepackt wird.

Das ist zwar sinnvoll, aber (wie oben schon geschrieben) nicht unbedingt 
notwendig. Du hast GNU ld in deiner Kommandozeile gesagt, dass er das 
.text-Segment an Adresse 0 tun soll (und genau das hat er gemacht).

Mach' das einfach richtig, dann funktioniert's auch ohne Linker-Script:

arm-none-eabi-ld -e 0 -o test_arm.elf 
--section-start=.interrupt_vector_table=0 xxx.o

Dann muss man nur noch (mit '.section ".interrupt_vector_table"') dafür 
gesorgt werden, dass die auch tatsächlich in der richtigen Section 
landet und alles ist gut.

von Uwe H. (Gast)


Lesenswert?

Danke dir Til für deine Mühe! Werde am WE mir mal das Seggerstudio
reinziehen, habe es schon runtergeladen, und mal schauen, was dein 
Beispielprogramm bringt.

Zur Qualität des GNU Codes sagt leider keiner etwas. Auch beim C 
Compiler hatte ich schon Übles erlebt, bei Optimierungsstufe Q1 hatte 
mir der Compiler eine Zeile wegoptimiert, die permanent auf das OUTTGL 
Register schreibt, sprich es toggelt.... Seitdem ist Q0 angesagt, 
entsprechend sieht der Code aus.....
BG

Uwe

von Dr. Sommer (Gast)


Lesenswert?

Uwe H. schrieb:
> bei Optimierungsstufe Q1 hatte
> mir der Compiler eine Zeile wegoptimiert, die

99,9% des Codes, der "Kaputt"/weg optimiert wird, ist schlicht falsch, 
und mit falschem Code darf der Compiler machen was er will. Auch wenn 
man mit -O0 kompiliert kann einen das später einholen. Daher sollte man 
lieber den Code korrigieren anstatt über den Optimizer zu lästern!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Uwe H. schrieb:
> Obwohl ich mit der Direktive .org genau angebe

Die Grundregel galt schon zu CP/M-Zeiten: wenn man verschiebliche
Objektdateien benutzt, dann legt der Linker fest, was wohin kommt.
.org ist dann keine sinnvolle Direktive.

Uwe H. schrieb:
> Zur Qualität des GNU Codes sagt leider keiner etwas.

Sie ist sehr viel besser als die der meisten Leute, die vor der
Tastatur sitzen. ;-)

von Uwe H. (Gast)


Lesenswert?

Ok, Jörg, dann verrate mir bitte mal, wie man dem Linker mitteilt, nicht 
verschiebbaren Code zu erzeugen, sprich Code mit absoluten Adressen, 
wobei relative Adressen nur Sinn machen, wenn die Programme im RAM 
laufen, im Flash verschiebt sich nichts....

von Markus F. (mfro)


Lesenswert?

Uwe H. schrieb:
> Ok, Jörg, dann verrate mir bitte mal, wie man dem Linker mitteilt, nicht
> verschiebbaren Code zu erzeugen, sprich Code mit absoluten Adressen,
> wobei relative Adressen nur Sinn machen, wenn die Programme im RAM
> laufen, im Flash verschiebt sich nichts....

Bei jedem Assembler, der Sections unterstützt, versteht sich .org als 
Offset zur Section-Startadresse, nicht als absolute Adresse.

Und wie man bestimmt, wo die Section hinkommt, wurde ja schon 
angesprochen.

von Dr. Sommer (Gast)


Lesenswert?

Benutz doch einfach ein Linker-Script, so wie es alle anderen auch 
machen. Kopier einfach das vom Hersteller aus dem Beispiel-Code. Damit 
erübrigen sich die ganzen Probleme.

Uwe H. schrieb:
> Ok, Jörg, dann verrate mir bitte mal, wie man dem Linker mitteilt, nicht
> verschiebbaren Code zu erzeugen,
Der Code von Linkern für Embedded-Plattformen erzeugt immer absoluten 
Code. Der Compiler bzw. Assembler, welche die .o Dateien erzeugt, 
hingegen nicht. Den macht der Linker erst absolut. Anders geht's auch 
gar nicht, was sollte der Linker tun wenn mehrere .o Dateien mit ".org 
0" auf die gleiche Adresse schreiben wollen? Daher werden zentral im 
Linker-Script den Symbolen Adressen zugewiesen. Bevor du mit Assembler 
anfängst schau dir doch vielleicht mal genau an, wie C-Projekte 
funktionieren. Da kannst du dann Stück für Stück allen C-Code durch 
Assembler ersetzen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Markus F. schrieb:
> Bei jedem Assembler, der Sections unterstützt, versteht sich .org als
> Offset zur Section-Startadresse, nicht als absolute Adresse.

Wirklichen Sinn hat das bloß nicht, denn man kann ja nie vorhersagen,
ob es nicht noch weitere Objekte gibt, die in der gleichen Section
etwas platzieren wollen.

OK, mit einer Ausnahme: wenn man sich überlagernde Sections haben
will.  Aber wofür sollte man das brauchen?  Der Linker kann auf der
Basis von Symbolnamen ja bereits überlagern (Common-Block-Feature
aus FORTRAN-Zeiten).

von Axel S. (a-za-z0-9)


Lesenswert?

Uwe H. schrieb:
> Zur Qualität des GNU Codes sagt leider keiner etwas. Auch beim C
> Compiler hatte ich schon Übles erlebt, bei Optimierungsstufe Q1 hatte
> mir der Compiler eine Zeile wegoptimiert, die permanent auf das OUTTGL
> Register schreibt

Das liegt mit an Sicherheit grenzender Wahrscheinlichkeit nicht am GNU 
Compiler, sondern an der Definition des Registers. Wahrscheinlich fehlt 
schlicht und einfach ein volatile an passender Stelle.

Uwe H. schrieb:
> Ok, Jörg, dann verrate mir bitte mal, wie man dem Linker mitteilt, nicht
> verschiebbaren Code zu erzeugen, sprich Code mit absoluten Adressen

Deine Ahnungslosigkeit scheint keine Grenzen zu kennen. Der Linker legt 
den Code natürlich auf feste Adressen. Das ist ja gerade sein Job. 
Allerdings kann er alles, was sich innerhalb der gleichen .section 
befindet, darin beliebig anordnen. das ist der Vertrag, den du mit dem 
Linker hast. Und wenn du irgendwas an feste Adressen legen mußt, dan 
pack es in eine eigene Section und tu die in dein Linkerscript.

Die GNU Toolchain ist wie ein Lego-Kasten: sehr mächtig, wenn man weiß 
was man tut. Wer einfach nur blind Steine aufeinander stapelt, wird 
damit aber nicht glücklich.

von Markus F. (mfro)


Lesenswert?

Uwe H. schrieb:
> Zur Qualität des GNU Codes sagt leider keiner etwas.

für die Qualität von Assemblercode ist ausschliesslich der Programmierer 
verantwortlich - da gibt's nix zu sagen.

von Scotty60 (Gast)


Lesenswert?

Sorry Markus, das ist eine Pauschalaussage, für die es aber paar wenige 
Ausnahmen geben kann! Wenn beim M0+ der Befehl mov r1, #0x80 erlaubt 
ist, siehe Cortex M0+ Programming Manual, und der Assembler macht daraus 
eine ARM V7 instruction, nämlich movew r1,#0x80, die erst ab M3 
verstanden wird, dann kann man dafür nicht den Programmierer 
verantwortlich machen und ihn mit Stammtischparolen konfrontieren! 
Natürlich hatte ich dem Assembler die CPU verraten (mcpu=cortex-m0plus), 
das rein präventiv! Ich stimme dir zu, wenn du sagen würdest, und das 
hast du bestimmt versucht, ein Assembler hat bei der 
(Maschinen)Codeerzeugung quasi keine Optionen, übersetzt also 1:1. 
Natürlich kann ihm auch mal dabei ein Fehler passieren, s.o., dennoch 
ist die Fehlerquote weitaus geringer als beim wesentlich komplexeren 
Compiler, der nicht umsonst generell als wartungsintensiv gilt! Als ich 
zuletzt vor 15 Jahren Code geschrieben hatte, seitdem machte ich nur 
noch Hardware/EMV, gab es kaum einen Monat, wo ein Compiler keinen Mist 
produzierte. Star diesbezüglich war damals der Cosmic Compiler.

von Markus F. (mfro)


Lesenswert?

Scotty60 schrieb:
> Sorry Markus, das ist eine Pauschalaussage, für die es aber paar wenige
> Ausnahmen geben kann! Wenn beim M0+ der Befehl mov r1, #0x80 erlaubt
> ist, siehe Cortex M0+ Programming Manual, und der Assembler macht daraus
> eine ARM V7 instruction, nämlich movew r1,#0x80, die erst ab M3
> verstanden wird, dann kann man dafür nicht den Programmierer
> verantwortlich machen und ihn mit Stammtischparolen konfrontieren!

Ich kenne mich mit dem M0+ nicht aus, aber

1.) Stammtischparolen liegen mir fern
2.) in meiner Kopie des Cortex-M0+ Technical Reference Manual kommt MOV 
mit einem immediate-Wert nicht als unterstützte Instruktion vor, 
lediglich MOVS
3.) mein gas übersetzt dein Statement nicht (auch nicht in irgendwas 
Falsches), sondern liefert die (zugegebenermassen nicht unbedingt 
erhellende) Fehlermeldung: "Error: cannot honour width suffix"

Und auch die Fehlermeldung lässt sich (wenn auch nur "um die Ecke") 
erklären: die einzigen "fass' die Flags nicht an" MOV-Instruktionen mit 
immediate-Werten, die es im Thumb-Instruktionset überhaupt gibt, sind 
die mit 32-Bit immediates (die wiederum aber der M0plus nicht 
unterstützt). Der Assembler versteht also "32 bit" und sagt: "nein, kann 
ich nicht".


[edit: Tippfehler korrigiert]

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Scotty60 schrieb:
> seitdem machte ich nur noch Hardware/EMV, gab es kaum einen Monat, wo
> ein Compiler keinen Mist produzierte. Star diesbezüglich war damals der
> Cosmic Compiler.

Ich hab schon ne Menge mit dem GNU Compiler gearbeitet und habe diverse 
Compiler Fehler gefunden, aber kein Einziges Mal war es einer der 
falschen Code generiert hat - höchstens ineffizienten Code. Die Leute, 
die hier im Forum darüber lästern dass der Compiler falschen Code 
generiert, sind meistens die, die nicht wissen was in C erlaubt ist und 
was nicht!

PS: Der Cosmic Compiler soll doch so supi sein, warum gibt man für den 
so viel Geld aus wenn er so fehlerhaft ist?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Scotty60 schrieb:
> wo ein Compiler keinen Mist produzierte.

Seltsame Erfahrungen.  Kommst mir gerade ein bisschen vor wie der
Falschfahrer … „Einer? Alle!“

Gerade im ARM-Bereich wird der GCC (und der darunter liegende Assembler)
tagtäglich von vielen Programmierern auf der Welt für produktiven Code
benutzt (also pay job, kein Hobby).  Meinst du nicht, dass derart
grundlegende Fehler dabei sehr schnell auffallen würden?

von c-hater (Gast)


Lesenswert?

Jörg W. schrieb:

> Die Grundregel galt schon zu CP/M-Zeiten: wenn man verschiebliche
> Objektdateien benutzt, dann legt der Linker fest, was wohin kommt.
> .org ist dann keine sinnvolle Direktive.

Das würde ich aber definitiv anders sehen. In nahezu jeder Architektur 
gibt es Speicherbereiche oder Teile davon, für die es absolut Sinn 
ergibt, schon im Quelltext entweder auf eine absolute Adresse oder 
zumindest auf ein bestimmtes Alignment ausgerichtet zu werden.

Und es ist natürlich ein sehr nützliches Feature, dies bereits im 
Quelltext festlegen (und kommentieren) zu können, statt auf Frickeleien 
mit irgendwelchen proprietären Make-Scripts angewiesen zu sein. Nö, 
wirklich Sinn ergäbe nur: Der Compiler/Assembler verwaltet das (soweit 
vom Programmierer explizit geschrieben) und teilt dem Linker mit, was 
aus seiner Sicht unveränderlich ist. Der Linker hat sich damit 
abzufinden und den Rest so zu lokalisieren, dass er passt. Er muss aber 
natürlich einen Fehler werfen, wenn sich dabei unauflösbare Widersprüche 
ergeben. Den das (und nur das) wäre eine sinnvolle Unterstützung des 
Programmierers.

> Sie ist sehr viel besser als die der meisten Leute, die vor der
> Tastatur sitzen. ;-)

Das allerdings ist leider nur zu wahr. Spricht allerdings meiner 
Erfahrung nach nicht besondern für die üblichen toolchains, sondern eher 
nur gegen die meisten, die selbige benutzen...

von Dr. Sommer (Gast)


Lesenswert?

c-hater schrieb:
> Und es ist natürlich ein sehr nützliches Feature, dies bereits im
> Quelltext festlegen (und kommentieren) zu können

Kann ja sein dass du das nützlich findest, aber die GNU Toolchain machts 
halt nicht so ;-)

c-hater schrieb:
> statt auf Frickeleien
> mit irgendwelchen proprietären Make-Scripts angewiesen zu sein.
Ich finde es ist eher eine Frickelei, wenn man die Adressen wild im 
Quellcode verteilt. Da ist es sauberer, wenn alle Speicherbereiche und 
-Adressen zentral und übersichtlich im Linker-Script für den konkreten 
Controller stehen (bei der GNU Toolchain ist übrigens nichts 
proprietär), und der Code abstrakt und somit portabler ist.

von W.S. (Gast)


Lesenswert?

Jörg W. schrieb:
> Gerade im ARM-Bereich wird der GCC

Du haust in die falsche Kerbe. Er hatte nicht vom GCC geschrieben: 
"war damals der Cosmic Compiler".



Uwe H. schrieb:
> Und hier stoße ich auf ein weiteres Problem. Obwohl ich mit der
> Direktive .org genau angebe, wo die Vektortabelle und der Maschinencode
> platziert werden sollen,...

In der ARM-Welt hat es sich als Standard etabliert, sowas wie ORG nicht 
zu bedienen und nicht zur Kenntnis nehmen zu wollen. Stattdessen muß man 
Moduln machen, die den Platz, wo was hin soll, etwa so formulieren 
(Keil):
1
                AREA    RESET, CODE, READONLY
2
3
oder
4
                AREA    |.ARM.__at_0x2FC|, CODE, READONLY

Also: ORG gibt's nicht und LTORG ist nur zum Abstapeln von 
Direktoperanden gedacht. Man kann nen Trick mit ALIGN und entsprechendem 
Argument benutzen, aber das ist m.E. letztlich Pfusch.

W.S.

von Scotty60 (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Ich hab schon ne Menge mit dem GNU Compiler gearbeitet und habe diverse
> Compiler Fehler gefunden, aber kein Einziges Mal war es einer der
> falschen Code generiert hat -

Also wenn man dich so hört, kommt man glatt zu Schluss, Compiler machen 
keine Fehler, benötigen keine Wartung! Frag mal einen 
Compilerhersteller, warum Compiler generell wartungsintensiv sind! 
Solltest du aber Compiler kennen, die absolut fehlerfrei sind, dann ab 
mit der Info ins Guinessbuch der Rekorde!!!! Und bitte erzähle uns auch 
keinen von fehlerfreier Software!

von Dr. Sommer (Gast)


Lesenswert?

Deiner "!"-Taste klemmt.

von Scotty60 (Gast)


Lesenswert?

Markus F. schrieb:
> 2.) in meiner Kopie des Cortex-M0+ Technical Reference Manual kommt MOV
> mit einem immediate-Wert nicht als unterstützte Instruktion vor,
> lediglich MOVS

Markus, da hast du Recht, danke für den Tipp! Generell gibt es bei der 
Regel mit dem "S" am Befehl (=Update des Statusregisters) einige 
Ausnahmen, etwa auch bei lsl, lsr, asrs, rors (ohne Anspruch auf 
Vollständigkeit!). Ich habe den fürchterlichen Verdacht, daß die 16 Bit 
Befehle namens Thumb (ich weiß, es gibt etwa eine Handvoll Ausnahmen) 
extrem viele Restriktionen ergeben, auch bei R8-R12, daß ich mich 
langsam nach den ARM 32 Bit Befehlen sehne (kennste da eine M Version?)! 
Verständlich, denn je weniger Bits der Opcode hat, desto weniger 
Möglichkeiten hat man, Stichwort 2^16 statt 2^32 (abzüglich Platz für 
immediate Bits). Vielleicht bin ich auch zu verwöhnt, denn als ich von 
31 Jahren anfing zu programmieren, hatte ich den Luxus, auf Motorola 
68000 programmieren zu dürfen, zwischen 12.000-20.000 Zeilen! Das hieß 
vorbildliche Orthogonalität des Befehlssatzes, in Sachen Adressierung 
konnte man weitgehend seine Phantasien ausleben! Ok, ich weiß, das ist 
unfair, denn 68000 Familie war CISC total. Natürlich reichten da keine 
1-2 Takte, verständlich.

von Markus F. (mfro)


Lesenswert?

Scotty60 schrieb:
> Markus F. schrieb:
>> 2.) in meiner Kopie des Cortex-M0+ Technical Reference Manual kommt MOV
>> mit einem immediate-Wert nicht als unterstützte Instruktion vor,
>> lediglich MOVS
>
> Markus, da hast du Recht, danke für den Tipp! Generell gibt es bei der
> Regel mit dem "S" am Befehl (=Update des Statusregisters) einige
> Ausnahmen, etwa auch bei lsl, lsr, asrs, rors (ohne Anspruch auf
> Vollständigkeit!). Ich habe den fürchterlichen Verdacht, daß die 16 Bit
> Befehle namens Thumb (ich weiß, es gibt etwa eine Handvoll Ausnahmen)
> extrem viele Restriktionen ergeben, auch bei R8-R12, daß ich mich
> langsam nach den ARM 32 Bit Befehlen sehne (kennste da eine M Version?)!
> Verständlich, denn je weniger Bits der Opcode hat, desto weniger
> Möglichkeiten hat man, Stichwort 2^16 statt 2^32 (abzüglich Platz für
> immediate Bits).

Nun, um ehrlich zu sein bin ich nie auf die Idee gekommen, auch nur eine 
einzige Zeile ARM Thumb mehr als unbedingt notwendig "von Hand" zu 
schreiben. Anständige C-Compiler erzeugen - wenn man damit umgehen kann 
- Code, der für >99% aller Anwendungsfälle mehr als ausreichend ist. Das 
restliche Prozent (ganz frühen Startup-Code, z.B.) kann man mit 
Inline-Assembly erschlagen. Mehr tu' ich mir nicht mehr an.

> Vielleicht bin ich auch zu verwöhnt, denn als ich von
> 31 Jahren anfing zu programmieren, hatte ich den Luxus, auf Motorola
> 68000 programmieren zu dürfen, zwischen 12.000-20.000 Zeilen! Das hieß
> vorbildliche Orthogonalität des Befehlssatzes, in Sachen Adressierung
> konnte man weitgehend seine Phantasien ausleben! Ok, ich weiß, das ist
> unfair, denn 68000 Familie war CISC total. Natürlich reichten da keine
> 1-2 Takte, verständlich.

Ähm, nö. Ein mc68060 schafft mit dem Grossteil des m68k Instruction-Sets 
mindestens einen Befehl pro Takt, in den allermeisten Fällen 
(superskalar) sogar zwei. ColdFire V4 nicht ganz so gut, aber ähnlich. 
Trotzdem: die Zeiten sind (leider) vorbei.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Scotty60 schrieb:
> Also wenn man dich so hört, kommt man glatt zu Schluss, Compiler machen
> keine Fehler, benötigen keine Wartung!

Ich musste meinen Compiler noch nie schmieren oder Kühlwasser
wechseln. :-)

Selbstverständlich machen Compiler Fehler, aber die, bei denen
tatsächlich falscher Code generiert wird, sind dabei in der völligen
Minderzahl. Gerade bei einem Compiler wie GCC ist die Bug-Datenbank
öffentlich, da kannst du das problemlos nachvollziehen. GCC hat sicher
seine Macken (gerade beim AVR kann Georg-Johann Lay dir ein Lied davon
singen), aber mittlerweile hat er eine Stabilität erreicht, dass man
oft genug mit einer Compilerversion produktiv arbeiten kann, die schon
viele Jahre alt ist.  Schau dir doch einfach mal an, wie viele Leute
hier noch mit der letzten WinAVR-Version aus dem Jahr 2010 AVRs
programmieren.  Bei ARMs ist es auch nicht grundlegend anders, außer
dass man halt für Architekturen wie Cortex-M0+ einen nicht ganz so
alten Compiler haben darf.  Aber ob man nun mit einem GCC 4.8, 5.x,
6.x oder 7.x arbeitet – funktionieren tut das Compilat mit dem einen
wie mit dem anderen, sofern man nicht gerade mit irgendwas so sehr
„auf Kante“ ist (bezüglich der Laufzeit), dass die letzten 10 % an
Optimierung wichtig sind.

Zu direkter Assemblerprogrammierung habe ich bei AVR noch ganz selten
gegriffen, seit ich ARMs in der Hand habe, noch nie.  Wozu auch?
Cortex-M hat ARM so aufgebaut, dass man sogar den Startup-Code komplett
in C schreiben kann, wenn man das möchte.  (Selbstverständlich heißt
das nicht, dass man deshalb den Assemblercode nicht wenigstens
rudimentär verstehen können sollte, wenn man in diesem Bereich
unterwegs ist.)

von Scotty60 (Gast)


Lesenswert?

Markus F. schrieb:
> Nun, um ehrlich zu sein bin ich nie auf die Idee gekommen, auch nur eine
> einzige Zeile ARM Thumb mehr als unbedingt notwendig "von Hand" zu
> schreiben.

Marcus, ich kann dich absolut verstehen! Ich betreibe meine Liebe zu 
Assembler auch nicht beruflich, und ich will auch keinen Religionskrieg 
gegen Hochsprachen starten! Aus meinem Ingenieurberuf habe ich mich vor 
Jahren frühzeitig verabschiedet. Aber gerne erinnere ich mich zurück, 
wie ich vor 31 Jahren angefangen habe, da geht es um Nostalgie. 
Natürlich ist mir klar, daß Portabilität und Aufwand bei Assembler 
schlecht sind, keine Frage. Aber dennoch lernt man nur mit Assembler 
eine Prozessorarchitektur am besten von Innen kennen, und ich wage zu 
behaupten, auch auf die Gefahr eines Shitstorms, daß Assembler für 
sicherheitskritische Anwendungen die mit Abstand beste Wahl ist, da viel 
transparenter und kürzerer und einfacheren Code! Und ein Assembler ist 
erheblich einfacher aufgebaut als der generell komplexe Compiler, so daß 
der Assembler erheblich weniger Fehler machen wird.

Den Höhepunkt (und das Ende) der 68000 Familie, den 68060 kenne ich 
leider persönlich nicht. Beim 68000er hatten die schnellsten Befehle 4 
Takte (68020 2 Takte bei Cache hit), die sich schnell vervielfachten bei 
komplexen Adressierungsarten. Der Vergleich zum 68060 ist etwas unfair 
mit seinen oft Eintaktbefehlen, da superskalare Architektur, wo komplexe 
CISC instructions in viele RISC Befehle zerlegt, die aber auf viele ALUs 
verteilt wurden.

Beitrag #5278193 wurde von einem Moderator gelöscht.
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Scotty60 schrieb:

> Aber gerne erinnere ich mich zurück,
> wie ich vor 31 Jahren angefangen habe, da geht es um Nostalgie.

Dann programmiere doch eine historische Architektur in Assembler,
einen Z80 oder sowas. ;-)

> Aber dennoch lernt man nur mit Assembler
> eine Prozessorarchitektur am besten von Innen kennen,

Bei Controllern muss man im Allgemeinen relativ wenig über den
Prozessor selbst wissen.  Das A und O bei Controllerprogrammierung
ist die Bedienung der Peripherie.  Die kannst du auch in einer
höheren Sprache genauso low-level wie in Assembler haben, wenn du
halt nicht solche Dinge wie ASF oder CubeMX oder dergleichen
benutzt.

> und ich wage zu
> behaupten, auch auf die Gefahr eines Shitstorms, daß Assembler für
> sicherheitskritische Anwendungen die mit Abstand beste Wahl ist, da viel
> transparenter und kürzerer und einfacheren Code!

Das mit dem kürzeren Code ist eine Mär.  Die wurde hier selbst bei
sehr simplen Beispielen bereits eindrucksvoll widerlegt, und wenn
das Programm komplexer als ein paar Kilobyte ist, dann ist es mit
der Übersicht in einem 50seitigen Assemblerprogramm sowieso schnell
Essig.

Anders sieht das sicher noch aus, wenn du in sowas wie einem ATtiny10
einen Mini-Controller realisierst mit sehr stark abgegrenztem
Aufgabenfeld.

> Und ein Assembler ist
> erheblich einfacher aufgebaut als der generell komplexe Compiler, so daß
> der Assembler erheblich weniger Fehler machen wird.

Der Assembler ist natürlich einfacher aufgebaut.  Es ist aber in der
überwiegenden Anzahl der Fälle nicht der Compiler selbst, der die
Fehler macht (dieser Mythos vom „wartungsaufwändigen“ Compiler, von
dem du den Eindruck erweckst, als würde er fehlerhaften Code am
laufenden Band produzieren, zieht sich nun schon durch den ganzen
Thread), sondern der fehleranfälligste Teil der Programmierung sitzt
immer noch vor der Tastatur.  Dieser Teil wiederum ist deutlich weniger
codesicher als ein Compiler. Der Compiler arbeitet stur seine formale
Sprachbeschreibung ab.  Wenn ich einem 10seitigen Hochsprachprogramm
ein 50seitiges Assemblerprogramm gegenüberstelle (ungefähr darauf
wird's wohl hinauslaufen), dann habe ich auch eine (grob) fünfmal so
hohe Fehlerwahrscheinlichkeit – mal in der Annahme, dass natürlich
der Programmierer jeweils „fit ist“, also keine grundlegenden Probleme
mit seiner Programmiersprache hat.

Beitrag #5278225 wurde von einem Moderator gelöscht.
Beitrag #5278246 wurde von einem Moderator gelöscht.
Beitrag #5278248 wurde von einem Moderator gelöscht.
Beitrag #5278249 wurde von einem Moderator gelöscht.
Beitrag #5278250 wurde von einem Moderator gelöscht.
Beitrag #5278251 wurde von einem Moderator gelöscht.
Beitrag #5278252 wurde von einem Moderator gelöscht.
Beitrag #5278253 wurde von einem Moderator gelöscht.
Beitrag #5278255 wurde von einem Moderator gelöscht.
Beitrag #5278257 wurde von einem Moderator gelöscht.
Beitrag #5278259 wurde von einem Moderator gelöscht.
Beitrag #5278260 wurde von einem Moderator gelöscht.
Beitrag #5278261 wurde von einem Moderator gelöscht.
Beitrag #5278262 wurde von einem Moderator gelöscht.
von Scotty60 (Gast)


Lesenswert?

Jörg W. schrieb:
> Wenn ich einem 10seitigen Hochsprachprogramm
> ein 50seitiges Assemblerprogramm gegenüberstelle (ungefähr darauf
> wird's wohl hinauslaufen), dann habe ich auch eine (grob) fünfmal so
> hohe Fehlerwahrscheinlichkeit

Hier werden Äpfel (Hochsprache) mit Birnen (Assembler) verglichen!
Wenn ein Assemblerprogramm 50 Seiten lang ist, dann werden die 10 Seiten 
Hochsprache in etwa 70 Seiten Assembler übersetzt werden, dazu auch noch 
schwer lesbar! Nicht selten erlebt man, daß Compiler die vielen Register 
nicht benutzen, stattdessen eine Stackorgie betrieben wird, daß es der 
Sau graust!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Scotty60 schrieb:
> Nicht selten erlebt man, daß Compiler die vielen Register nicht
> benutzen, stattdessen eine Stackorgie betrieben wird, daß es der Sau
> graust!

Solange du bei derart unbelegten pauschalisierten Aussagen bleibst,
lohnt es sich nicht, weiter zu diskutieren.

Es kann ja sein, dass du noch nie einen gut funktionierenden Compiler
in den Fingern hattest, aber dann verallgemeinere doch bitte nicht
von dem, was du kennst, auf moderne Compiler.

ps: OK, wenn du einem Compiler natürlich die Optimierung untersagst,
dann produziert er in der Tat den von dir hier dargelegten Codewust.

: Bearbeitet durch Moderator
Beitrag #5278286 wurde von einem Moderator gelöscht.
Beitrag #5278287 wurde von einem Moderator gelöscht.
Beitrag #5278290 wurde von einem Moderator gelöscht.
Beitrag #5278291 wurde von einem Moderator gelöscht.
Beitrag #5278294 wurde von einem Moderator gelöscht.
Beitrag #5278295 wurde von einem Moderator gelöscht.
Beitrag #5278296 wurde von einem Moderator gelöscht.
Beitrag #5278297 wurde von einem Moderator gelöscht.
Beitrag #5278311 wurde von einem Moderator gelöscht.
von Christopher J. (christopher_j23)


Lesenswert?

Scotty60 schrieb:
> Markus F. schrieb:
>> Nun, um ehrlich zu sein bin ich nie auf die Idee gekommen, auch nur eine
>> einzige Zeile ARM Thumb mehr als unbedingt notwendig "von Hand" zu
>> schreiben.
>
> Marcus, ich kann dich absolut verstehen! Ich betreibe meine Liebe zu
> Assembler auch nicht beruflich, und ich will auch keinen Religionskrieg
> gegen Hochsprachen starten!

Wenn man Assembler als Hobby betreibt, dann ist das völlig OK. Bei mir 
war es vor allem die Neugierde zu "wissen was die Welt, im Innersten 
zusammenhält", weil ich eben nicht mit Assembler, sondern mit C und 
anderen "Hochsprachen" aufgewachsen bin und wenn man die komplette Kette 
von der 1. Instruktion bis zum Aufruf von main() bei einem Cortex-M 
verstehen will, dann ist Assembler zumindest hilfreich. Program-Counter 
und Stack-Pointer waren für mich vormals komplett böhmische Dörfer. Den 
einzig sinnvollen Einsatz von Assembler, der mir bisher in freier 
Wildbahn begegnet ist, sind jedoch lediglich Teile von RTOS-Kerneln 
gewesen und damit meine ich auch nicht den kompletten Kernel, sondern 
typischerweise ist es eben dann nur der eigentliche context switch der 
bis auf die letzte Instruktion optimiert ist. Für alles andere ist C 
einfach praktikabler und nur weil man theoretisch besser sein kann als 
der Compiler, trifft das in der Praxis in gefühlt >99% der Fälle nicht 
zu.

Ich kann dazu nur folgenden Vortrag von Matt Godbolt empfehlen:
https://www.youtube.com/watch?v=bSkpMdDe4g4&t=1688s

Die Pointe des Vortrags ist etwa zwischen Minute 28 und 32. Die Zeit 
davor ist lediglich ein x86-Assembler-Crashkurs aber auch sehr 
interessant.

: Bearbeitet durch User
von Scotty60 (Gast)


Lesenswert?

Jörg W. schrieb:
> lohnt es sich nicht, weiter zu diskutieren.

Stimmt! Wahrscheinlich hatten wir in der Automobilindustrie nur Mist 
verwendet gepaart mit Vollidioten von Ingenieuren.... Leider gab es 
damals noch nicht mikrocontroller.net, wo wir gelernt hätten, die 
Optimierung einzuschalten und bei der Variablendeklaration das Wort 
"register" zu verwenden, sarkasm off!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Christopher J. schrieb:
> eile von RTOS-Kerneln gewesen und damit meine ich auch nicht den
> kompletten Kernel, sondern typischerweise ist es eben dann nur der
> eigentliche context switch der bis auf die letzte Instruktion optimiert
> ist.

Nicht nur optimiert: dort werden ja hart irgendwelce CPU-Ressourcen
umgeschaltet (Stack & PC), da möchte man wohl in der Tat exakt
hinschreiben, was zu tun ist.

Ich glaube, der berühmte Kommentar im V6 UNIX "You are not supposed
to understand this" bezog sich auch auf so eine Stelle.  Dennis Ritchie
hat im Netz eine Erklärung dafür hinterlassen.

von Markus F. (mfro)


Lesenswert?

Jörg W. schrieb:
> Ich glaube, der berühmte Kommentar im V6 UNIX "You are not supposed
> to understand this" bezog sich auch auf so eine Stelle.  Dennis Ritchie
> hat im Netz eine Erklärung dafür hinterlassen.

Der Kommentar lautete m.W. präzise "You are not expected to understand 
this".

Das wirklich spassige an der Sache ist aber, dass die ursprünglichen 
Programmierer es wohl auch nicht ganz verstanden haben. Im Nachgang 
stellte sich nämlich heraus, dass die besagte Stelle noch einen Bug 
hatte ;).

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Markus F. schrieb:
> Das wirklich spassige an der Sache ist aber, dass die ursprünglichen
> Programmierer es wohl auch nicht ganz verstanden haben.

Yep, genau deshalb haben sie den Kommentar so geschrieben. Einen
Inline-Assembler hatten sie dazumals noch nicht.

Beitrag #5278361 wurde von einem Moderator gelöscht.
von Christopher J. (christopher_j23)


Lesenswert?

Den Kommentar "You are not expected to understand this" kannte ich noch 
nicht aber man lernt ja nie aus. Zum Glück gibt es aber relativ viel 
"Dokumentation" zu diesem Kommentar ;)

Unter anderem https://thenewstack.io/not-expected-understand-explainer/

Und natürlich noch der Source-Code dazu:
https://github.com/dspinellis/unix-history-repo/blob/Research-V6-Snapshot-Development/usr/sys/ken/slp.c#L318

: Bearbeitet durch User
Beitrag #5278369 wurde von einem Moderator gelöscht.
von Nop (Gast)


Lesenswert?

Scotty60 schrieb:
> Nicht selten erlebt man, daß Compiler die vielen Register
> nicht benutzen, stattdessen eine Stackorgie betrieben wird, daß es der
> Sau graust!

Das ist für sicherheitskritische Anwendungen irrelevant, solange am Ende 
der Orgie stets das Richtige rauskommt. Die Entwicklungszeiten mit 
Assembler sind vor allem deswegen viel länger als etwa in C, weil das 
Debuggen viel länger dauert. Das dauert deswegen länger, weil mehr 
Fehler eingebaut werden, wenn es sich nicht um kleine Codestellen 
handelt.

Wenn man initial mehr Fehler drin hat, ist die Wahrscheinlichkeit aber 
höher, daß am Ende davon noch welche drinbleiben. Selbst 100% code 
coverage hilft einem da nicht zwingend weiter.

Und bei der mangelhaften Wartbarkeit des Codes ist man dann noch gar 
nicht angekommen. 10 Seiten C wird der nachfolgende Programmierer 
nämlich viel schneller verstehen als 50 Seiten Assembler.

Beitrag #5278374 wurde von einem Moderator gelöscht.
Beitrag #5278375 wurde von einem Moderator gelöscht.
Beitrag #5278378 wurde von einem Moderator gelöscht.
Beitrag #5278394 wurde von einem Moderator gelöscht.
Beitrag #5278412 wurde von einem Moderator gelöscht.
von Scotty60 (Gast)


Lesenswert?

Nop schrieb:
> 10 Seiten C wird der nachfolgende Programmierer
> nämlich viel schneller verstehen als 50 Seiten Assembler.

Nop, ich stimme dir uneingeschränkt zu, daß die Fehleranfälligkeit in 
Assembler deutlich höher ist, d'accord! Allerdings wird man bei hoch 
sicherheitskritischen Anwendungen sich sicherlich auch den Assemblercode 
anschauen, und dann werden aus den 10 Seiten C mindestens 70 Seiten 
Assembler (gegenüber 50 selbstgeschriebenen), der schwer zu verstehen 
ist, besonders bei den häufigen Stackorgien. Fakt ist nun mal, daß der 
erzeugte Assemblercode meistens schwerer zu verstehen ist als 
selbstkreierter, womit das Debuggen im Disassemblypart ganz lustig wird. 
Sicherlich wird man erst den Hochsprachenteil debuggen, aber beim 
schnellen Aufspüren des Fehlers schaut man sich auch den Assemblerteil 
an, um herauszufinden, hat der Compiler gepatzt oder hat man schlampig 
programmiert.

von Scotty60 (Gast)


Lesenswert?

Christopher J. schrieb:
> Ich hab dir mal ein absolut minimalistisches Blinky (für STM32)
> angehängt,

Hallo Christopher!

Ich habe mal deine Files als Vorlage genommen, nun sieht das Disassembly 
schon verdammt gut aus, die Reihenfolge Vektoren - Programmcode stimmt 
jetzt, hab nochmals vielen Dank! Zwar sieht das Intel Hexfile schlecht 
aus, funktioniert nicht, aber das werde ich auch noch hinbekommen. 
Vermutlich der falsche Typ, da Intelhex nur 16 Bit Adressen kennt laut 
Wikipedia, auch wenn Atmel Studio das File klaglos nimmt und selber das 
Ihexformat erzeugt, zumindest beim SAMD10D14, dessen 16kb Flash 
Adressraum bei 0 beginnt. Das wahre Problem aber ist, wie bekomme ich 
das Zeug debuged? Wenn ich Atmel Studio kein compilierbares C File gebe, 
wird das Debugmenue deaktiviert. Mit dem Assemblerfile kann AS nichts 
anfangen. Ich befürchte, ich muss die die hier schon propagierte Lösung 
nehmen, C Projekt erstellen, die C-Dateien rausschmeißen und dann das 
Assemblerfile integrieren.... Manno, sind das Klimmzüge!
Gruß

Uwe

von Christopher J. (christopher_j23)


Lesenswert?

Naja, wenn du es richtig martialisch willst, dann nimmst du einfach nur 
den GDB-Server der zu deinem Debugger passt, also sehr wahrscheinlich 
OpenOCD oder den J-Link GDB-Server, öffnest dann deine .elf mit GDB, 
verbindest dich mit dem GDB-Server und debuggst das in der Kommandozeile 
bzw. im TUI. Alternativ kannst du eines der unzähligen GDB-Frontends 
verwenden, die entweder eigenständig sind, wie z.B. 
https://github.com/cs01/gdbgui oder andere, die wiederum in IDEs 
integriert sind, z.B. "Native Debug" für Visual Studio Code oder 
QT-Creator mit "Bare-Metal"-Plugin. Letzteres benutze ich selber.

Das direkt in AS zu machen ist sicherlich die deutlich bequemere 
Variante. Am bequemsten ist es vermutlich alle C-Dateien einfach drin zu 
lassen und aus der main() einfach eine asm_main() aufzurufen, die du 
dann irgendwo in ASM implementierst. Dann hast du halt nicht mehr die 
absolute Kontrolle über den Startup aber bist vermutlich deutlich 
schneller bei einem funktionierenden Ergebnis.

von Uwe H. (Gast)


Angehängte Dateien:

Lesenswert?

Christopher J. schrieb:
> wenn du es richtig martialisch willst, dann nimmst du einfach nur
> den GDB-Server

Auja, ich mag es martialisch! Allerdings muss ich vorher einen Fehler 
wegbekommen, der auch bei deinen unveränderten Files auftritt, nämlich 
es wird eine ungerade Startadresse in der Vektortabelle erzeugt, um 1 zu 
hoch, obwohl dein Programm an einer geraden, und durch 4 teilbaren 
Adresse beginnt. Diesen Fehler habe ich auch, der Rest stimmt in den 
Hexfiles, wobei bei deinem Hexfile der Eintrag des SPs fehlt, siehe 
Anhänge.

von Dr. Sommer (Gast)


Lesenswert?

Uwe H. schrieb:
> nämlich
> es wird eine ungerade Startadresse in der Vektortabelle erzeugt, um 1 zu
> hoch,

Das ist korrekt und muss so. Da alle Instruktionen 2 oder 4 Byte lang 
sind, sind alle Adressen gerade, wodurch das unterste Bit nicht benötigt 
wird. Dies wird daher dazu verwendet, um anzugeben, ob beim Sprung an 
die jeweilige Adresse in den Thumb Mode (1) oder den ARM Mode (0) 
geschaltet werden soll. Da die Cortex-M nur Thumb können, muss das 
unterste Bit jeder Sprung-Adresse immer 1 sein, inkl. der Adressen im 
ISR-Vektor.

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Uwe H. schrieb:
>> nämlich
>> es wird eine ungerade Startadresse in der Vektortabelle erzeugt, um 1 zu
>> hoch,
>
> Das ist korrekt und muss so. Da alle Instruktionen 2 oder 4 Byte lang
> sind, sind alle Adressen gerade, wodurch das unterste Bit nicht benötigt
> wird. Dies wird daher dazu verwendet, um anzugeben, ob beim Sprung an
> die jeweilige Adresse in den Thumb Mode (1) oder den ARM Mode (0)

Gut zu sehen, wie weit die Vorbereitung auf ARM-Assembler-Programmierung 
schon gediehen ist.

von Uwe H. (Gast)


Lesenswert?

Oha, danke Dr. Sommer, das wußte ich echt nicht, was sind die Dinger 
komplex!!!

von Uwe H. (Gast)


Lesenswert?

Dr. Sommer, gilt diese Regel mit dem +1 nur für den Resetvektor?

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Gut zu sehen, wie weit die Vorbereitung auf ARM-Assembler-Programmierung
> schon gediehen ist.
Hehehe!

Uwe H. schrieb:
> Oha, danke Dr. Sommer, das wußte ich echt nicht, was sind die
> Dinger
> komplex!!!
Ja, und deswegen nutzt man auch Hochsprachen...

Uwe H. schrieb:
> Dr. Sommer, gilt diese Regel mit dem +1 nur für den Resetvektor?
Nein, auch für Sprünge/Funktionsaufrufe, wenn die "B[L]X" Instruktionen 
genutzt werden (X= eXchange, aktiviert die Modus-Umschaltung). Bei "B" 
wird das Bit ignoriert. Der Linker fügt das +1 automatisch hinzu wenn du 
Sprungmarken/Labels nutzt.

von Nop (Gast)


Lesenswert?

Der Beispiel-Assembler-Code ist zwar sehr kurz, aber zeigt, daß nicht 
alles was man in der Sprache schreibt gut sein muß. Der ARM braucht 
keine händischen Adressrechnungen, um die verschiedenen Register eines 
IO-Bausteins anzusprechen.

von Christopher J. (christopher_j23)


Lesenswert?

Du meinst sicher solche Stellen wie
1
  ldr R1, =0x40021000  // = RCC_APB2 Base
2
  add R1, #0x18    // add offset of APB2ENR to R1
3
  // The last two steps are the same as ldr R1, =0x40021018 
4
5
  ldr R1, =0x44244444  // Configure PIN13 as PP output @ 2MHz
6
7
  str R1, [R0]    // Write config to GPIOC_CRH

Die überflüssigen adds sind tatsächlich quasi sinnfreies Padding. Ich 
wollte als ich das geschrieben hatte, das die Größe des Binärprogramms 
in Byte genau durch 42 teilbar ist. Eine Anspielung darauf steht sogar 
ganz oben in der ersten Zeile :D

Ne, im ernst: Der Code war nie dazu gedacht einen Schönheitspreis zu 
gewinnen. Man könnte das sicher viel eleganter lösen und die Größe auf 
~60 Byte bekommen. Das war aber im Prinzip nie das Ziel von diesem 
Programm, sondern es ging mir persönlich nur darum einmal ein sehr 
minimales Programm in Assembler geschrieben zu haben und naja, es 
funktioniert sogar, d.h. die LED blinkt.

von S. R. (svenska)


Lesenswert?

Uwe H. schrieb:
> nämlich es wird eine ungerade Startadresse in der Vektortabelle erzeugt

Eine gerade Adresse führt sofort zu einem HardFault.

von Christopher J. (christopher_j23)


Lesenswert?

Uwe H. schrieb:
> Diesen Fehler habe ich auch, der Rest stimmt in den
> Hexfiles, wobei bei deinem Hexfile der Eintrag des SPs fehlt, siehe
> Anhänge.

Ich habe nicht so den Plan von Hexfiles aber wenn ich dein Hexfile nehme 
und es mittels Objcopy in ein Binary umwandle kommt exakt das gleiche 
Binary heraus, wie wenn ich das Binary aus meiner .elf erstelle.

Die zweite Zeile des Hex-Files erinnert auch verdächtig an das Binary:

.hex
1
:1020000000500020092000084FF001004FEA0010A6

.bin
1
00000000: 0050 0020 0920 0008 4ff0 0100 4fea 0010  .P. . ..O...O...

Ich frage mich allerdings sowieso wofür man bei den ARM-Controllern noch 
das hex-Format benutzen sollte. Irgendwelche low-level Bootloader wollen 
dann doch lieber direkt das Binary und für alles andere benutze ich das 
elf-Format.

von Uwe H. (Gast)


Lesenswert?

Hallo Christopher!

Ich hatte mal dein super dokumentiertes Beispiel total umgeschrieben. 
Kein Wunder, STM und SAMD10D14 sind total anders von der Peripherie. 
Auch hast du bei deinem M3 einen viel größeren Befehlssatz, den mein M0+ 
nicht versteht, bei vielen Befehlen gehörte noch das 'S' dran, etwa bei 
lsl, sub, mov. Ja, der M0+ ist total auf kleines Silizium getrimmt, 
damit der Strom spart auf Teufel komm raus.

Ergebnis: Der Blinker funktioniert, super!!!

Allerdings ist es mir ein Rätsel, warum er funktioniert. :-)

Du verwendest bei den 32 Bit Immediate Ladebefehlen die 
Pseudoin-struktion LDR rx,=0x......... Du hättest auch Mov32 verwenden 
können, die dann in Movew und movt umgewandelt wird. Ok, du bist 
schneller mit dieser literalen Adressierung, gut. Jedenfalls wird dein 
LDR Befehl erwartungsgemäß in eine PC relative Adressierung zerlegt, 
nichts Aufregendes. Dann werden diese 32 Bit Immediates abgelegt im 
literal pool, auch ok. Aber was da abgelegt wird, verstehe ich nicht. 
Konkret:
1
ldr r0, =0x41004400   // DIR Register
2
movs r1,#0x80
3
strb r1,[r0,#2]         @PA23=output 
4
ldr r0, =0x4100441c     // set the pointer to OUTTGL
5
  
6
strb r1,[r0,#2]         @toggle PA23
7
ldr r3,=#500000          //delay
8
delay:  subs R3 , #1
9
  bne delay  // branch (goto) "delay" if not equal
10
  b toggle        // goto "toggle"

 Der Disassembler zeigt mir folgendes Szenario an:
1
00000008 <gpioconfig>:
2
   8:  4804        ldr  r0, [pc, #16]  ; (1c <delay+0x8>)
3
   a:  2180        movs  r1, #128  ; 0x80
4
   c:  7081        strb  r1, [r0, #2]
5
   e:  4804        ldr  r0, [pc, #16]  ; (20 <delay+0xc>)
6
7
00000010 <toggle>:
8
  10:  7081        strb  r1, [r0, #2]
9
  12:  4b04        ldr  r3, [pc, #16]  ; (24 <delay+0x10>)
10
11
00000014 <delay>:
12
  14:  3b01        subs  r3, #1
13
  16:  d1fd        bne.n  14 <delay>
14
  18:  e7fa        b.n  10 <toggle>
15
16
  1a:  44000000   strmi  r0, [r0], #-0
17
  1e:  441c4100   ldrmi  r4, [ip], #-256  ; 0xffffff00
18
  22:  a1204100       ; <UNDEFINED> instruction:

Aus den Immediates 0x41004400, 0x4100441c, 500000 macht er

                   0x44000000, 0x441c4100  0xa1204100

Theoretisch müsste die CPU auf die falschen Adressen zugreifen, sprich 
die GPIO Ports um Meilen verfehlen, was aber nicht der Fall ist. Ich 
erbitte Aufklärung, da ich bei Tante Google nichts zur Verschlüsselung 
finde, da sieht es nämlich logisch aus, etwa bei 
http://www.eng.auburn.edu/~nelson/courses/elec2220/slides/ARM%20prog%20model%202%20addressing.pdf.

: Bearbeitet durch Moderator
von Dr. Sommer (Gast)


Lesenswert?

Uwe H. schrieb:
> Aus den Immediates 0x41004400, 0x4100441c, 500000 macht er
>                    0x44000000, 0x441c4100  0xa1204100

Nö... Schau dir mal ganz genau die Adressen an, die geladen werden. Der 
Disassembler fasst die Bytes "falsch " zu 32bit Words zusammen (bzw. 
anders als der Assembler). Wie disassemblierst Du?

von Uwe H. (Gast)


Lesenswert?

Hallo Dr. Sommer!

Dr. Sommer schrieb:
> Wie disassemblierst Du?

Diese Frage verstehe ich nicht! Das File Format ist elf32-littlearm, der 
Befehl lautet arm-none-eabi-objdump -D -S miniblink.elf 
>disassembly.txt.

Zur Zeit kann ich noch keine reinen Assemblerprogramme debuggen, muss 
mir da noch etwas installieren. Aber auf jeden Fall stimmen die geholten 
Adressen aus dem literal pool, denn sonst würde die CPU nicht das OUTTGL 
Register treffen.

Mit dem falsch zusammenfassen Bytes gebe ich dir überwiegend Recht, man 
könnte fast alles zusammen puzzlen, allerdings fehlt eine Zahl, denn 
500000 =0x7A120, und da fehlt nur noch die 7......

von Dr. Sommer (Gast)


Lesenswert?

Uwe H. schrieb:
> Diese Frage verstehe ich nicht! Das File Format ist elf32-littlearm, der
> Befehl lautet arm-none-eabi-objdump -D -S miniblink.elf
>>disassembly.txt.
Aber die Antwort ist richtig :D "-d" find ich schöner, weil er dann 
nicht versucht die Daten zu disassemblieren.

Uwe H. schrieb:
> Zur Zeit kann ich noch keine reinen Assemblerprogramme debuggen, muss
> mir da noch etwas installieren.
Wer C debuggen kann, kann auch Assembler debuggen.

Uwe H. schrieb:
> allerdings fehlt eine Zahl, denn
> 500000 =0x7A120, und da fehlt nur noch die 7......
Ja, die 7 hast du nicht mit kopiert, die muss da aber noch folgen.

Offenbar schreibt der Assembler zwei Dummy-0-Bytes in das Binary, damit 
die Words 4-Byte-Aligned sind. Schreib einfach mal ein "nop" ans Ende 
von "delay", welches dann die Dummy-Bytes ersetzt. Dann zeigt der 
Disassembler die Words richtig an. Der GCC macht genau das beim 
Kompilieren von C-Code anscheinend automatisch. Vielleicht reicht ja 
"-d" statt "-D" auch um das richtig anzuzeigen.

von Dr. Sommer (Gast)


Lesenswert?

PS: Ich habs grad mal selber ausprobiert. Das hier
1
.thumb
2
3
foo:
4
  ldr r0, =0x01234567
Assemblisiert und so wieder disassembliert
1
arm-none-eabi-as test.S -o test.o && arm-none-eabi-objdump -d test.o
ergibt
1
Disassembly of section .text:
2
3
00000000 <foo>:
4
   0:  4800        ldr  r0, [pc, #0]  ; (4 <foo+0x4>)
5
   2:  0000        .short  0x0000
6
   4:  01234567   .word  0x01234567
Also korrekte Darstellung, die Füll-Bytes werden korrekt separat 
gezeigt. Was machst du anders?

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Schreib einfach mal ein "nop" ans Ende von "delay"

Sollte man ohnehin viel öfter machen. ^^

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Sollte man ohnehin viel öfter machen. ^^

Einfach mal Pause machen, und sich 1/SYSCLK lang Ruhe gönnen.

von Uwe H. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> "-d" find ich schöner

Stimmt total! Jetzt kommt ein lupenreines Disassambyl listing heraus, 
die Adressen stimmen, danke dir für den Tipp!!! Mit dem Alignment nop 
konnte ich mir daher ersparen:

Disassembly of section .text:

00000000 <min_vectors>:
   0:  20000200   .word  0x20000200
   4:  00000009   .word  0x00000009

00000008 <gpioconfig>:
   8:  4804        ldr  r0, [pc, #16]  ; (1c <delay+0x8>)
   a:  2180        movs  r1, #128  ; 0x80
   c:  7081        strb  r1, [r0, #2]
   e:  4804        ldr  r0, [pc, #16]  ; (20 <delay+0xc>)

00000010 <toggle>:
  10:  7081        strb  r1, [r0, #2]
  12:  4b04        ldr  r3, [pc, #16]  ; (24 <delay+0x10>)

00000014 <delay>:
  14:  3b01        subs  r3, #1
  16:  d1fd        bne.n  14 <delay>
  18:  e7fa        b.n  10 <toggle>
  1a:  0000        .short  0x0000
  1c:  41004400   .word  0x41004400
  20:  4100441c   .word  0x4100441c
  24:  0007a120   .word  0x0007a120

Zum Schluss möchte ich Allen hier danken für ihre Hilfe, besonders 
Christopher für das Lernbeispiel!!! Diese "Anschiebehilfe" war wohl 
notwendig, denn mit den ARMs habe ich mir echt etwas Kompliziertes 
angelacht, dagegen war die 68000 Familie, Freescale (nun NXP, ich weiß) 
und AVR Spielzeug. Aber es macht Spaß. Naja, um ARM kommt man nicht 
herum, sind bei uCs wohl schon seit Jahren Marktführer.

von Dr. Sommer (Gast)


Lesenswert?

Uwe H. schrieb:
> Stimmt total! Jetzt kommt ein lupenreines Disassambyl

Wenn du jetzt noch lokale Sprungmarken verwendest, werden auch deine 
Funktionen nicht mehr zerpflückt... dafür ist der Quellcode dann weniger 
gut lesbar.

von Uwe H. (Gast)


Lesenswert?

Lokale Sprungmarken? Sind das Labels, die ich eh verwende??

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?


von Uwe H. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Wer C debuggen kann, kann auch Assembler debuggen

Vom persönlichen Können ja. Aber ich kann Atmel Studio kein reines 
Assemblerprogramm unterschieben, ich muss immer ein C File (main()) als 
trojanisches Pferd mitliefern!

von Dr. Sommer (Gast)


Lesenswert?

z.B. so:
1
.syntax unified
2
.cpu cortex-m0plus
3
.thumb
4
5
.type  function1, %function
6
function1:
7
  ldr r0, =0x41004400   // DIR Register
8
  movs r1,#0x80
9
  strb r1,[r0,#2]         @PA23=output 
10
  ldr r0, =0x4100441c     // set the pointer to OUTTGL
11
    
12
  1:
13
    strb r1,[r0,#2]         @toggle PA23
14
    ldr r3,=#500000          //delay
15
  2:  subs R3 , #1
16
    bne 2b  // branch (goto) "delay" if not equal
17
    b 1b        // goto "toggle"
18
19
  bx lr
20
  .pool
21
22
.type  function1, %function
23
function2:
24
1:
25
  b 1b

Dann sind in der Disassembly die Funktionen am Stück:
1
Disassembly of section .text:
2
3
00000000 <function1>:
4
   0:  4804        ldr  r0, [pc, #16]  ; (14 <function1+0x14>)
5
   2:  2180        movs  r1, #128  ; 0x80
6
   4:  7081        strb  r1, [r0, #2]
7
   6:  4804        ldr  r0, [pc, #16]  ; (18 <function1+0x18>)
8
   8:  7081        strb  r1, [r0, #2]
9
   a:  4b04        ldr  r3, [pc, #16]  ; (1c <function1+0x1c>)
10
   c:  3b01        subs  r3, #1
11
   e:  d1fd        bne.n  c <function1+0xc>
12
  10:  e7fa        b.n  8 <function1+0x8>
13
  12:  4770        bx  lr
14
  14:  41004400   .word  0x41004400
15
  18:  4100441c   .word  0x4100441c
16
  1c:  0007a120   .word  0x0007a120
17
18
00000020 <function2>:
19
  20:  e7fe        b.n  20 <function2>
20
  22:  46c0        nop      ; (mov r8, r8)

Ohne das ".pool" werden Constant Pools hier ganz ans Ende gepackt, was 
zwar nicht schlimm ist aber etwas komisch aussieht.

Uwe H. schrieb:
> ich muss immer ein C File (main()) als
> trojanisches Pferd mitliefern!
Glaube ich kaum, geht bestimmt irgendwie. Mit Atmel Studio hab ich aber 
keine Erfahrung, ich benutze meistens eclipse, da ist das kein Problem.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
>> ich muss immer ein C File (main()) als
>> trojanisches Pferd mitliefern!
> Glaube ich kaum, geht bestimmt irgendwie.

Die haben für Assemblerprojekte beim ARM einfach mal keine Vorlage.

Wird vermutlich so gut wie nie nachgefragt …

von Dr. Sommer (Gast)


Lesenswert?

Jörg W. schrieb:
> Die haben für Assemblerprojekte beim ARM einfach mal keine Vorlage.

Das klingt schon wahrscheinlicher. Aber woher die ELF-Datei kommt 
sollte doch den Debugger nicht interessieren.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Aber woher die ELF-Datei kommt sollte doch den Debugger nicht
> interessieren.

Vermutlich bekommt man den Studio-eigenen Debugger jedoch nur
angeworfen, wenn man ihm ein Projekt aufsetzt, und das will er dann
natürlich erstmal „bauen“, bevor er den Debugger anwirft …

Vermutlich könnte man sich nun hinsetzen und schauen, wie man ihm
ein ARM-Assemblerprojekt definiert, aber man könnte seine Zeit auch
mit anderen Dingen verbringen.

von Dr. Sommer (Gast)


Lesenswert?

Jörg W. schrieb:
> und das will er dann natürlich erstmal „bauen“, bevor er den Debugger
> anwirft …

Soll er doch... Man kann doch wohl ein Projekt nur aus .S Dateien machen 
(zB durch Löschen der C Dateien) und von Atmel Studio builden lassen?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Keine Ahnung, ich benutze es auch nicht. :)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.