2016-06-04 27 views
0

Angenommen, ich nehme ein c++ Programm und kompilieren es in eine Assembly (.S) Datei.Convert C++ in C

Dann nehme ich diese Assembly-Datei und "disassemblieren" das in C, würde dieser Code auf einer anderen Plattform neu kompilierbar sein?

Der Grund warum ich das frage ist, dass die Plattform, auf der ich versuche zu entwickeln, keinen c++ Compiler hat, weil es einen c Compiler hat.

+0

Wenn Ihr Dis-Assembler gültigen C-Code gibt, warum nicht? aber zuerst müssen Sie überprüfen, ob es einen gültigen c-Code gibt. – SHR

+0

@SHR Worüber ich mir Sorgen mache ist, dass es 'uint16_t' in' uint8_t' verwandelt und so was macht. – DarthRubik

+0

@DarthRubik schau dir das an, es ist vielleicht eine bessere Lösung: http://llvm.org/releases/3.1/docs /FAQ.html#translatecxx – SHR

Antwort

2

Ja, es ist in der Tat möglich, wie Sie beschreiben. Nein, es ist nicht portierbar für andere CPU-Architekturen, Betriebssysteme und Compiler-Tripel als Ihre.

Mal sehen warum. Nehmen Sie einige grundlegende C++ Code ...

#include <iostream> 

int main() 
{ 
    std::cout << "Hello, world!\n"; 
    return 0; 
} 

Wenden wir uns dies in Assembler mit g++, auf einem x86-64 Linux-Box (Ich drehte Optimierungen auf und verworfen Debug-Symbole, in Zweck) ...

$ g++ -o test.s -O3 -S test.cpp 

und das Ergebnis ist ...

.file "test.cpp" 
    .section .rodata.str1.1,"aMS",@progbits,1 
.LC0: 
    .string "Hello, world!\n" 
    .section .text.unlikely,"ax",@progbits 
.LCOLDB1: 
    .section .text.startup,"ax",@progbits 
.LHOTB1: 
    .p2align 4,,15 
    .globl main 
    .type main, @function 
main: 
.LFB1027: 
    .cfi_startproc 
    subq $8, %rsp 
    .cfi_def_cfa_offset 16 
    movl $.LC0, %esi 
    movl $_ZSt4cout, %edi 
    call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 
    xorl %eax, %eax 
    addq $8, %rsp 
    .cfi_def_cfa_offset 8 
    ret 
    .cfi_endproc 
.LFE1027: 
    .size main, .-main 
    .section .text.unlikely 
.LCOLDE1: 
    .section .text.startup 
.LHOTE1: 
    .section .text.unlikely 
.LCOLDB2: 
    .section .text.startup 
.LHOTB2: 
    .p2align 4,,15 
    .type _GLOBAL__sub_I_main, @function 
_GLOBAL__sub_I_main: 
.LFB1032: 
    .cfi_startproc 
    subq $8, %rsp 
    .cfi_def_cfa_offset 16 
    movl $_ZStL8__ioinit, %edi 
    call _ZNSt8ios_base4InitC1Ev 
    movl $__dso_handle, %edx 
    movl $_ZStL8__ioinit, %esi 
    movl $_ZNSt8ios_base4InitD1Ev, %edi 
    addq $8, %rsp 
    .cfi_def_cfa_offset 8 
    jmp __cxa_atexit 
    .cfi_endproc 
.LFE1032: 
    .size _GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main 
    .section .text.unlikely 
.LCOLDE2: 
    .section .text.startup 
.LHOTE2: 
    .section .init_array,"aw" 
    .align 8 
    .quad _GLOBAL__sub_I_main 
    .local _ZStL8__ioinit 
    .comm _ZStL8__ioinit,1,1 
    .hidden __dso_handle 
    .ident "GCC: (GNU) 5.3.1 20151207 (Red Hat 5.3.1-2)" 
    .section .note.GNU-stack,"",@progbits 

das Chaos ist der Preis, den wir für die Ausnahmebehandlung bezahlen, Vorlagen und Namensräume. Lassen Sie uns diese von Hand in C zerlegen, verwirft die Ausnahmebehandlung Tabellen für eine sauberere Ansicht ...

/* std::ostream */ 
typedef struct 
{ 
    /* ... */ 
} _ZSo; 

/* extern operator<<(std::basic_ostream&, const char*); */ 
extern _ZStlsIst11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc(); 

/* namespace std { extern ostream cout; } */ 
extern _ZSo _ZSt4cout; 

/* Our string, of course! */ 
static const char* LC0 = "Hello, world!\n"; 

int main() 
{ 
    _ZStlsIst11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc(&_ZSt4cout, LC0); 
    return 0; 
} 

unlesbar scheint, noch tragbar, nicht wahr? Genau jetzt ist es so. Aber dieser Code wird nicht funktionieren! Sie müssen _ZSo (std::ostream) noch in C struct Begriffe definieren, ganz zu schweigen von allen Ausnahmebehandlungskram.

Die Dinge werden nahezu unmöglich, sobald sie anfangen zu verwenden try/throw/catch. Ich meine, es gibt absolut keine Möglichkeit, dass __cxa_allocate_exception oder __cxa_throw jemals tragbar sein wird! Der einzige Weg um dies zu tun ist, um alle Ihre Programm neu schreiben (und das schließt alle Bibliotheken, die Sie verwenden, auch die Standard-Bibliothek!), Um die langsamere/longjmp Annäherung an Ausnahmen anstelle von zero-cost exception handling zu verwenden.

Nicht zuletzt wird ein nicht-menschlicher Disassembler höchstwahrscheinlich selbst bei den einfachsten Eingaben nicht richtig funktionieren. Denken Sie daran, dass es auf den niedrigsten Ebenen von Sachen (a.k. ein Maschinencode und eine Assemblersprache) kein Konzept von Typen gibt. Sie können nie wissen, ob ein Register eine vorzeichenbehaftete ganze Zahl ist, und eine vorzeichenlose ganze Zahl oder im Grunde nichts anderes. Der Compiler kann auch mit dem Stapelzeiger nach Belieben spielen, was den Job verschlechtert.

Sobald die Kompilierung abgeschlossen ist, löscht der Compiler, der keine zukünftige Disassemblierung erwartet, alle diese wertvollen Informationen, da Sie diese normalerweise zur Laufzeit nicht benötigen. In den meisten Fällen lohnt sich das Disassemblieren nicht, wenn überhaupt, und wahrscheinlich suchen Sie nach einer anderen Lösung. Die Übersetzung von einer Sprache der höheren Mittelstufe in eine Sprache der unteren Ebene in eine Sprache der unteren Mittelstufe führt dies zu einem Extrem und nähert sich den Grenzen dessen, was in was anderes übersetzt werden kann.

+0

Was passiert, wenn ich keine Bibliotheken benutze und alles selbst schreibe (keine printfs oder couts)? – DarthRubik

+0

@DarthRubik: Die Implementierung der Standardbibliothek ist per Definition nicht portabel. Wie würden Sie "printf" selbst auf vollständig tragbare Weise implementieren? Es gibt keine Möglichkeit. Deshalb existieren die Standardbibliotheken an erster Stelle; Sie bieten eine gemeinsame, portable Schnittstelle zu allen verschiedenen Plattformen. Wie auch immer, du musst immer noch mit der Ausnahmebehandlung umgehen. – 3442

+0

Dies ist für einen Mikrocontroller (so würde ich überhaupt keine printf haben) – DarthRubik