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.
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
@SHR Worüber ich mir Sorgen mache ist, dass es 'uint16_t' in' uint8_t' verwandelt und so was macht. – DarthRubik
@DarthRubik schau dir das an, es ist vielleicht eine bessere Lösung: http://llvm.org/releases/3.1/docs /FAQ.html#translatecxx – SHR