كيف يمكنك الحصول على مخرجات المجمع من مصدر C/C++ في دول مجلس التعاون الخليجي؟
سؤال
كيف واحد يفعل هذا؟
إذا كنت أرغب في تحليل كيفية تجميع شيء ما، فكيف يمكنني الحصول على رمز التجميع المنبعث؟
المحلول
استخدم ال -S
خيار دول مجلس التعاون الخليجي (أو g++).
gcc -S helloworld.c
سيؤدي هذا إلى تشغيل المعالج المسبق (cpp) عبر helloworld.c، وإجراء الترجمة الأولية ثم التوقف قبل تشغيل المجمع.
افتراضيًا، سيؤدي هذا إلى إخراج ملف helloworld.s
.لا يزال من الممكن تعيين ملف الإخراج باستخدام -o
خيار.
gcc -S -o my_asm_output.s helloworld.c
بالطبع هذا لا يعمل إلا إذا كان لديك المصدر الأصلي.البديل إذا كان لديك ملف الكائن الناتج فقط هو استخدامه objdump
, ، عن طريق تعيين --disassemble
خيار (أو -d
للنموذج المختصر).
objdump -S --disassemble helloworld > helloworld.dump
يعمل هذا الخيار بشكل أفضل إذا تم تمكين خيار التصحيح لملف الكائن (-g
في وقت الترجمة) ولم يتم تجريد الملف.
جري file helloworld
سيعطيك بعض المؤشرات حول مستوى التفاصيل التي ستحصل عليها باستخدام objdump.
نصائح أخرى
سيؤدي هذا إلى إنشاء رمز asm مع رمز C + أرقام الأسطر المتشابكة لمعرفة الخطوط التي تولد أي رمز بسهولة أكبر.
# create assembler code:
c++ -S -fverbose-asm -g -O2 test.cc -o test.s
# create asm interlaced with source lines:
as -alhnd test.s > test.lst
عثر عليه في خوارزميات للمبرمجين, ، الصفحة 3 (وهي الصفحة الخامسة عشرة الإجمالية لملف PDF).
سطر الأوامر التالي من مدونة كريستيان جاربين
g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt
لقد قمت بتشغيل G++ من نافذة DOS على نظام Win-XP، مقابل روتين يحتوي على طاقم ضمني
c:\gpp_code>g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt
horton_ex2_05.cpp: In function `int main()':
horton_ex2_05.cpp:92: warning: assignment to `int' from `double'
يتم تجميع المخرجات من خلال التعليمات البرمجية التي تم إنشاؤها والتي تتخللها كود C++ الأصلي (يظهر كود C++ كتعليقات في دفق asm الذي تم إنشاؤه)
16:horton_ex2_05.cpp **** using std::setw;
17:horton_ex2_05.cpp ****
18:horton_ex2_05.cpp **** void disp_Time_Line (void);
19:horton_ex2_05.cpp ****
20:horton_ex2_05.cpp **** int main(void)
21:horton_ex2_05.cpp **** {
164 %ebp
165 subl $128,%esp
?GAS LISTING C:\DOCUME~1\CRAIGM~1\LOCALS~1\Temp\ccx52rCc.s
166 0128 55 call ___main
167 0129 89E5 .stabn 68,0,21,LM2-_main
168 012b 81EC8000 LM2:
168 0000
169 0131 E8000000 LBB2:
169 00
170 .stabn 68,0,25,LM3-_main
171 LM3:
172 movl $0,-16(%ebp)
استخدم رمز التبديل -S
g++ -S main.cpp
أو أيضًا مع دول مجلس التعاون الخليجي
gcc -S main.c
انظر أيضا هذا
إذا كان ما تريد رؤيته يعتمد على ربط الإخراج، فقد يكون objdump على ملف كائن الإخراج/القابل للتنفيذ مفيدًا أيضًا بالإضافة إلى gcc -S المذكور أعلاه.إليك نصًا مفيدًا جدًا من تأليف Loren Merritt يقوم بتحويل صيغة objdump الافتراضية إلى صيغة nasm الأكثر قابلية للقراءة:
#!/usr/bin/perl -w
$ptr='(BYTE|WORD|DWORD|QWORD|XMMWORD) PTR ';
$reg='(?:[er]?(?:[abcd]x|[sd]i|[sb]p)|[abcd][hl]|r1?[0-589][dwb]?|mm[0-7]|xmm1?[0-9])';
open FH, '-|', '/usr/bin/objdump', '-w', '-M', 'intel', @ARGV or die;
$prev = "";
while(<FH>){
if(/$ptr/o) {
s/$ptr(\[[^\[\]]+\],$reg)/$2/o or
s/($reg,)$ptr(\[[^\[\]]+\])/$1$3/o or
s/$ptr/lc $1/oe;
}
if($prev =~ /\t(repz )?ret / and
$_ =~ /\tnop |\txchg *ax,ax$/) {
# drop this line
} else {
print $prev;
$prev = $_;
}
}
print $prev;
close FH;
أظن أنه يمكن استخدام هذا أيضًا في إخراج gcc -S.
حسنًا، كما قال الجميع، استخدم الخيار -S.إذا كنت تستخدم الخيار -save-temps، فيمكنك أيضًا الحصول على ملف تمت معالجته مسبقًا(.i)، ملف التجميع (.s) وملف الكائن (*.o).(احصل على كل واحد منهم باستخدام -E، -S، و -c.)
كما أشار الجميع، استخدم -S
خيار لدول مجلس التعاون الخليجي.أود أيضًا أن أضيف أن النتائج قد تختلف (بشكل كبير!) اعتمادًا على ما إذا كنت تضيف خيارات التحسين أم لا (-O0
من أجل لا شيء، -O2
للتحسين العدواني).
في معماريات RISC على وجه الخصوص، غالبًا ما يقوم المترجم بتحويل التعليمات البرمجية إلى ما هو أبعد من التعرف عليه أثناء إجراء التحسين.إنه أمر مثير للإعجاب ورائع أن ننظر إلى النتائج!
كما ذكرنا سابقًا، انظر إلى علامة -S.
من المفيد أيضًا النظر إلى مجموعة أعلام "-fdump-tree"، وبالأخص "-fdump-tree-all"، والتي تتيح لك رؤية بعض الأشكال الوسيطة لدول مجلس التعاون الخليجي.غالبًا ما تكون هذه أكثر قابلية للقراءة من المجمّع (على الأقل بالنسبة لي)، وتتيح لك رؤية كيفية أداء تمريرات التحسين.
استخدم الخيار -S:
gcc -S program.c
إذا كنت تبحث عن تجميع LLVM:
llvm-gcc -emit-llvm -S hello.c
لا أرى هذا الاحتمال بين الإجابات، ربما لأن السؤال من عام 2008، لكن في عام 2018 يمكنك استخدام موقع Matt Goldbolt على الإنترنت https://godbolt.org
يمكنك أيضًا استنساخ git محليًا وتشغيل مشروعه https://github.com/mattgodbolt/compiler-explorer
من: http://www.delorie.com/djgpp/v2faq/faq8_20.html
gcc -c -g -Wa,-a,-ad [خيارات دول مجلس التعاون الخليجي الأخرى] foo.c > foo.lst
في بديل عن إجابة Phirephly أو مجرد استخدام -s كما قال الجميع.
فيما يلي خطوات رؤية/طباعة رمز التجميع لأي برنامج C على نظام Windows الخاص بك
وحدة التحكم/المحطة/موجه الأوامر:
اكتب برنامج C في محرر أكواد C مثل كتل التعليمات البرمجية واحفظه بامتداد .c
تجميعها وتشغيلها.
بمجرد التشغيل بنجاح، انتقل إلى المجلد الذي قمت بتثبيت برنامج التحويل البرمجي gcc الخاص بك فيه وقم بإعطاء الملف
الأمر التالي للحصول على ملف ".s" من الملف ".c".
C:\ gcc> gcc -S المسار الكامل لملف C ENTER
أمر مثال (كما في حالتي)
C:\gcc> gcc -S D:\Aa_C_Certified\alternate_letters.c
يؤدي هذا إلى إخراج ملف ".s" من الملف ".c" الأصلي
4 .بعد هذا اكتب الأمر التالي
C;\gcc> cpp filename.s أدخل
أمر مثال (كما في حالتي)
C;\gcc> cpp Alternative_letters.s
سيؤدي هذا إلى طباعة/إخراج رمز لغة التجميع بالكامل لبرنامج C الخاص بك.
استخدم "-S" كخيار.يعرض إخراج التجميع في المحطة.
أردت مؤخرًا معرفة تجميع كل وظيفة في البرنامج
هذه هي الطريقة التي فعلت ذلك.
$ gcc main.c // main.c source file
$ gdb a.exe // gdb a.out in linux
(gdb) disass main // note here main is a function
// similary it can be done for other functions
-save-temps
وقد ذكر هذا في https://stackoverflow.com/a/17083009/895245 ولكن اسمحوا لي أن أوضح ذلك بشكل أكبر.عندما تفعل:
gcc -save-temps -c -o main.o main.c
ج الرئيسية
#define INC 1
int myfunc(int i) {
return i + INC;
}
والآن، إلى جانب الإخراج الطبيعي main.o
, ، يحتوي دليل العمل الحالي أيضًا على الملفات التالية:
main.i
هي مكافأة وتحتوي على الملف المملوك مسبقًا المطلوب:# 1 "main.c" # 1 "<built-in>" # 1 "<command-line>" # 31 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 32 "<command-line>" 2 # 1 "main.c" int myfunc(int i) { return i + 1; }
main.s
يحتوي على التجميع الذي تم إنشاؤه المطلوب:.file "main.c" .text .globl myfunc .type myfunc, @function myfunc: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl %edi, -4(%rbp) movl -4(%rbp), %eax addl $1, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size myfunc, .-myfunc .ident "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0" .section .note.GNU-stack,"",@progbits
إذا كنت تريد القيام بذلك لعدد كبير من الملفات، ففكر في استخدام بدلاً من ذلك:
-save-temps=obj
الذي يحفظ الملفات الوسيطة في نفس الدليل مثل ملف -o
إخراج الكائن بدلاً من دليل العمل الحالي، وبالتالي تجنب تعارضات الأسماء الأساسية المحتملة.
انتهت ميزة هذا الخيار -S
هو أنه من السهل إضافته إلى أي برنامج نصي للبناء، دون التدخل كثيرًا في البناء نفسه.
شيء رائع آخر حول هذا الخيار هو إذا قمت بإضافته -v
:
gcc -save-temps -c -o main.o -v main.c
إنه يعرض في الواقع الملفات الصريحة المستخدمة بدلاً من الملفات المؤقتة القبيحة الموجودة أسفلها /tmp
, ، لذلك من السهل معرفة ما يحدث بالضبط، والذي يتضمن خطوات المعالجة المسبقة/التجميع/التجميع:
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu main.c -mtune=generic -march=x86-64 -fpch-preprocess -fstack-protector-strong -Wformat -Wformat-security -o main.i
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -fpreprocessed main.i -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase-strip main.o -version -fstack-protector-strong -Wformat -Wformat-security -o main.s
as -v --64 -o main.o main.s
تم الاختبار في Ubuntu 19.04 amd64 وGCC 8.3.0.
إليك حل لـ C باستخدام gcc :
gcc -S program.c && gcc program.c -o output
هنا يقوم الجزء الأول بتخزين مخرجات التجميع للبرنامج بنفس اسم الملف مثل البرنامج ولكن مع تغيير .س بامتداد، يمكنك فتحه كأي ملف نصي عادي.
يقوم الجزء الثاني هنا بتجميع برنامجك للاستخدام الفعلي وإنشاء ملف قابل للتنفيذ لبرنامجك باسم ملف محدد.
ال برنامج.ج المستخدم أعلاه هو اسم البرنامج الخاص بك و انتاج هو اسم الملف القابل للتنفيذ الذي تريد إنشاءه.
راجع للشغل، إنها أول مشاركة لي على StackOverFlow :-}