使用GDB调试已编译的C程序以学习汇编编程

时间:2017-07-01 17:30:48

标签: c gcc assembly gdb

我对gdb很新。我写了一个非常简单的你好世界节目

import android.os.Bundle;

import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;

import java.util.ArrayList;

public class ViewDatabase extends AppCompatActivity {
 private static final String TAG = "ViewDatabase";

 private DatabaseReference databaseReference;
 private String userID;

 private ListView mListView;

 @Override
 protected void onCreate(@Nullable Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.view_database_layout);

  mListView = (ListView) findViewById(R.id.listview);
  databaseReference = FirebaseDatabase.getInstance().getReference();



  databaseReference.addValueEventListener(new ValueEventListener() {
   @Override
   public void onDataChange(DataSnapshot dataSnapshot) {
    showData(dataSnapshot);
   }

   @Override
   public void onCancelled(DatabaseError databaseError) {

   }
  });

 }

 private void showData(DataSnapshot dataSnapshot) {
  userinfo user = dataSnapshot.getValue(userinfo.class);

  Log.d(TAG, "showData: name: " + user.getName());
  Log.d(TAG, "showData: Mobile: " + user.getMob());
  Log.d(TAG, "showData: Vehicle: " + user.getVehicle());
  Log.d(TAG, "showData: Address: " + user.getaddress());

  ArrayList < String > array = new ArrayList < > ();
  array.add(user.getName());
  array.add(user.getMob());
  array.add(user.getVehicle());
  array.add(user.getaddress());
  ArrayAdapter adapter = new
  ArrayAdapter(this, android.R.layout.simple_list_item_1, array);
  mListView.setAdapter(adapter);
 }


}

我用 public class userinfo { public String name; public String mob; public String vehicle; public String address; public userinfo() { } public userinfo(String name, String mob, String vehicle, String address) { this.name = name; this.mob = mob; this.vehicle = vehicle; this.address = address; } public String getName() { return name; } public String getMob() { return mob; } public String getVehicle() { return vehicle; } public String getaddress() { return address; } } } 编译它以添加调试符号

#include <stdio.h>

int main() {
  printf("Hello world\n");
  return 0;
}

由于我不熟悉gdb,我不知道接下来要做什么。我希望能够使用gdb来检查汇编代码。这就是我在IRC上被告知的事情。

2 个答案:

答案 0 :(得分:2)

首先,启动程序以准确停在main函数的开头。

(gdb) start

切换到装配布局,以便在单独的窗口中以交互方式查看装配说明。

(gdb) layout asm

使用stepinexti命令逐步执行该程序。当您遍历程序中的汇编指令时,您将看到装配窗口中的当前指令指针移动。

答案 1 :(得分:2)

printf几乎是你想要用来学习汇编的最后一个函数,库调用会在以后出现,但你不需要使用库/系统调用。使用调试器将使用系统调用引导您进入鼠窝。尝试这样的事情,特别是如果你想通过这个练习学习汇编语言。

unsigned int fun ( unsigned int a, unsigned int b )
{
    return(a^b^3);
}

gcc -O2 -c so.c -o so.o
objdump -D so.o

Disassembly of section .text:

0000000000000000 <fun>:
   0:   89 f0                   mov    %esi,%eax
   2:   83 f0 03                xor    $0x3,%eax
   5:   31 f8                   xor    %edi,%eax
   7:   c3                      retq   

我强烈建议您避免使用x86作为第一个指令集。尝试更干净的东西......

arm-none-eabi-gcc -O2 -c so.c -o so.o
arm-none-eabi-gcc -O2 -c -mthumb  so.c -o so.o
arm-none-eabi-objdump -D so.o

00000000 <fun>:
   0:   2303        movs    r3, #3
   2:   4059        eors    r1, r3
   4:   4048        eors    r0, r1
   6:   4770        bx  lr

msp430-gcc -O2 -c so.c -o so.o
msp430-objdump -D so.o

00000000 <fun>:
   0:   3f e0 03 00     xor #3, r15 ;#0x0003
   4:   0f ee           xor r14,    r15 
   6:   30 41           ret

认真对待这一个是第一个指令集,msp430接近它但是这个最有意义,不幸的是gnu汇编语法与书不匹配,也不幸的是在八进制的世界思想然后我们认为hex现在...

pdp11-aout-gcc -O2 -c so.c -o so.o
pdp11-aout-objdump -D so.o


00000000 <_fun>:
   0:   1166            mov r5, -(sp)
   2:   1185            mov sp, r5
   4:   15c0 0003       mov $3, r0
   8:   1d41 0006       mov 6(r5), r1
   c:   7840            xor r1, r0
   e:   1d41 0004       mov 4(r5), r1
  12:   7840            xor r1, r0
  14:   1585            mov (sp)+, r5
  16:   0087            rts pc

适合所有人的好模拟器或硬件,最好在模拟器中学习,而不是在真实硬件上学习......

我通过编写反汇编器,手臂和拇指学到的大部分指令集都属于这一类,因为它们是固定的指令长度(如果你避免使用thumb2扩展)。或者只是写一个模拟器,msp430和pdp11属于这一类。后者中的任何一个都是下午的项目,前者是一个长周末项目。你会比普通人更了解每个指令集,甚至一些人已经在其中编程了一段时间。

如果你坚持使用x86(我强烈建议你远离这个),请使用像pcemu这样的8086/8088模拟器并坚持原始指令集,使用nasm或a86或其他任何需要的方法来执行此操作。即使在那时它也没有那么好的指令集,但是当时比现在更有意义。 bitsavers很好地扫描了原始英特尔文档的搜索能力版本,这是最好的起点。

arm docs at arm(寻找armv5的架构参考手册,我认为他们现在称之为)。 msp430只是看看wikipedia指令集是否有pdp11谷歌它并使用C来机器代码来反汇编弄清楚语法。

如果你真的想玩得开心从opencores获得琥珀色核心它是一个arm2 / 3,几乎所有指令都与armv4相同,后来可以使用gnu工具。使用verilator从内部构建和模拟并查看工作处理器。理解这就像吸收100名程序员并为他们提供编程任务并获得1到100种不同的解决方案一样,采用指令集并为100名工程师提供实施任务的任务,您可以获得1到100种不同的解决方案。 Arm本身已经为相同的指令集多次重新设计了它们的核心,更不用说少数合法的克隆了。

建议订购pdp11,msp430,拇指,手臂,然后mips,如果你仍然觉得你需要拆解一些x86。 PIC12 / 14简单而有教育意义(应该花半个小时到一个小时来制作一个模拟器),6502,z80,8051,6800和其他一些历史上也很有教育意义的x86来查看文档但是没有必要编写程序。如果你从一个好的开始,那么每个第N个指令集从第二个指令集开始就容易得多。它们比不同的更相似,但你确实可以看到不同的东西,比如如何在没有标记的情况下做事情等等......我遗漏了其他一些指令集,这些指令集仍然可以在硅片中使用,或者由于各种原因而感兴趣。

另一种方法是安装clang / llvm并快速或长时间查看llc可以生成的每个指令集(编译为bitcode /字节码然后使用llc来执行任何指令集的后端)。像上面一样,使用相同的代码,看看不同的指令集看起来至少与编译器一样,它的设置非常有教育意义,有助于在心理上了解如何将编程任务分解为这些原子步骤。