汇编之小事例汇总

目录

 知识预备:shell编程小脚本

运行步骤:

1、交换2个内存数据 

2: 汇编完成 冒泡

3:体验异常处理过程:

简化版:

 4:体验汇编到c的转换

前提:在同一目录下运行,不然可能需要指明目录,没试过,读者可自行尝试

 知识预备:shell编程小脚本

//终端1脚本:
root@ubuntu:/mnt/U_share/caogao/ARM/swap$ cat gdbs.sh 
#! /bin/bash
arm-linux-gcc $1.s -o $1.o -c -g
arm-linux-ld $1.o -o $1.elf -Ttext=0x0
qemu-system-arm -machine xilinx-zynq-a9 -m 256M -serial stdio -kernel $1.elf     -S -s


//终端二脚本:
#! /bin/bash
arm-none-linux-gnueabi-gdb *.elf    //也可将 *.elf 替换成 $1.elf

运行步骤:

终端1运行:

root@ubuntu:/mnt/U_share/caogao/ARM/swap$ bash gdbs.sh swap 
//swap为程序名,每个不一样,$1本质是替换,详情可查询Liunx的shell脚本的编写
//如果脚本用*.s .o .elf 那么需要将不同的程序置于不同的目录下,就可不写 第二个参数swap
arm-linux-ld: warning: cannot find entry symbol _start; defaulting to 00000000

终端二运行:

root@ubuntu:/mnt/U_share/caogao/ARM/swap$ bash gdb.sh 
GNU gdb 6.8
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-build_pc-linux-gnu --target=arm-cortex_a8-linux-gnueabi"...
(gdb) target remote 127.0.0.1:1234
Remote debugging using 127.0.0.1:1234    //端口必须是1234,IP可回环,可本机IP
[New Thread 1]
0x00000000 in a ()
Current language:  auto; currently asm
(gdb) l            //显示程序
1	/*a=10,b=20 @:表示注释*/
2	a: .word 0x10   @ int a[1]={0x10};
3	b: .word 0x20   @ int b[1]={0x14};
4	.global _swap
5	_swap:
6	    ldr r0,=a   @伪指令 r0 = a
7	    ldr r1,[r0] @get a[0] value
8	    ldr r2,=b   @get b
9	    ldr r3,[r2] @get b[0]
10
(gdb) l
11	    str r3,[r0]
12	    str r1,[r2]
13	    nop
(gdb) b 13    //设置断点为13行
Breakpoint 1 at 0x20: file swap.s, line 13.
(gdb) c       //运行至断点,可s一步一步运行
Continuing.

Breakpoint 1, _swap () at swap.s:13
13	    nop    //作用:辅助延时,占位,设断点
(gdb) x/2 0x0    //从0地址开始看两个数据
0x0 <a>:	0x00000020	0x00000010
(gdb) q    
The program is running.  Exit anyway? (y or n) y

显示寄存器的值:    p $r0        p r0:看变量r0的值
x/n  0xy :查看从y地址开始的n个数据

1、交换2个内存数据 

root@ubuntu:/mnt/U_share/caogao/ARM/swap$ cat swap.s 
/*a=10,b=20 @:表示注释*/
a: .word 0x10   @ int a[1]={0x10};
b: .word 0x20   @ int b[1]={0x14};
.global _swap
_swap:
    ldr r0,=a   @伪指令 r0 = a
    ldr r1,[r0] @get a[0] value
    ldr r2,=b   @get b
    ldr r3,[r2] @get b[0]

    str r3,[r0]
    str r1,[r2]
    nop

运行结果:

(gdb) x/2 0x0
0x0 <a>:	0x00000010	0x00000020
(gdb) c
Continuing.

Breakpoint 1, _swap () at swap.s:13
13	    nop
(gdb) x/2 0x0
0x0 <a>:	0x00000020	0x00000010

2: 汇编完成 冒泡

buf: .word 0x33,0x55,0x44,0x11,0x22 @int buf[5]={0x33,...,0x22};
len: .word 4*4

.global _maopao
_maopao:
    ldr r0,=buf @ get buf first addr
    mov r9,#16  @ get buf tail addr
loop:
    ldr r1,[r0]
    ldr r2,[r0,#4]
    cmp r1,r2
    strgt r2,[r0]
    strgt r1,[r0,#4]

    add r0,r0,#4    @r0 offest 4 bytes
    cmp r0,r9
    blt loop

    ldr r0,=buf     @r0--->buf
    sub r9,r9,#4    @tail - 4
    cmp r0,r9
    blt loop

    nop

运行结果:

(gdb) b 24
Breakpoint 1 at 0x50: file maopao.s, line 24.
(gdb) x/5 0x0
0x0 <buf>:	0x00000033	0x00000055	0x00000044	0x00000011
0x10 <buf+16>:	0x00000022
(gdb) c      
Continuing.

Breakpoint 1, loop () at maopao.s:24
24	    nop
(gdb) x/5 0x0
0x0 <buf>:	0x00000011	0x00000022	0x00000033	0x00000044
0x10 <buf+16>:	0x00000055

3:体验异常处理过程:

.global u_add
.global u_sub
.globl _start
_start: 
	b	reset
	ldr	pc, _undefined_instruction
	ldr	pc, _software_interrupt
	ldr	pc, _prefetch_abort
	ldr	pc, _data_abort
	ldr	pc, _not_used
	ldr	pc, _irq
	ldr	pc, _fiq
/*定义异常向量表的空指针,配合上面异常向量表进行相应的跳转,在后面可以改函数指针的指向,如13行*/
_undefined_instruction: .word _undefined_instruction
_software_interrupt:	.word swi_handler
_prefetch_abort:	.word _prefetch_abort
_data_abort:		.word _data_abort
_not_used:		.word _not_used
_irq:			.word _irq
_fiq:			.word _fiq

reset:
	/* 设置cpu模式为SVC模式 */
    /*寄存器的基本方式:先清再或,确保安全*/
	mrs	r0, cpsr
	bic	r0, r0, #0x1f  
	orr	r0, r0, #0xd3 
	msr	cpsr,r0

	/* 设置异常向量表起始地址、根据arm的api规定的格式*/
	ldr	r0, =_start
	mcr	p15, 0, r0, c12, c0, 0	@Set VBAR

    /*用户需要设置的初始化*/
    ldr sp, stacktop  /*设置svc sp*/
    sub r6, sp , #64  /*计算user需要指向的栈顶地址*/

    /*切换到用户模式*/
	mrs	r0, cpsr
	bic	r0, r0, #0x1f  
	orr	r0, r0, #0x10 
	msr	cpsr,r0

    mov sp, r6  /*设置user sp*/

    /*跳转到应用程序*/
    bl	_main


_main:
    mov r0, #3
    mov r1, #4
    ldr r3,=mymem
    str r0,[r3]
    str r0,[r3,#4]

    bl u_add
    bl u_sub
    mov r3, r0
    nop
    nop
loop:
    b loop 

u_add:
    stmfd sp!, {lr} /*连同返回地址一起进入sp指向的栈,用于后续返回*/
    ldr r0,=mymem
    mov r1,#0
    str r1,[r0,#8]
    swi 0     /*产生软中断异常*/
    ldr r1,[r0]
    ldmfd sp!, {pc} /*执行完出栈,根据lr返回*/

u_sub:
    stmfd sp!, {lr}
    swi 1   /*产生软中断异常*/
    ldmfd sp!, {pc}

sys_add:
    stmfd sp!, {lr}
    ldr r0,=mymem
    ldr r1,[r0]
    ldr r2,[r0,#4]
    add r3,r1,r2
    str r3,[r0]
    ldmfd sp!, {pc}

sys_sub:
    stmfd sp!,{lr}
    ldr r0,=mymem
    ldr r1,[r0]
    ldr r2,[r0,#4]
    sub r3,r1,r2
    str r3,[r0]
    ldmfd sp!, {pc}

/*swi 异常处理函数  处于svc模式*/
swi_handler:
    stmfd sp!, {r1-r12,lr}  /*r1-r12:简写,r1到r12*/
    /*区分中断,这里还能优化中断号*/
//    ldr r0,=mymem   /*将中断信号类型从内存中取出来*/
//    ldr r1,[r0,#8]

    /*寄存器里面的编码*/
//    sub r0,lr,#4
//    ldr r1,[r0]   //再次优化成一句指令
    ldr r1,[lr,#-4]

    and r1,r1,#1
    cmp r1,#0 
    /*调用真正的加、减法函数*/
    bleq sys_add 
    blne sys_sub
    ldmfd sp!, {r1-r12,pc}^
/*设置栈空间,一般是一片空间,然后自己规划每个模式所使用的栈空间*/
/*然后规定不同的栈顶指针,见34行*/
stack: .space 64*8
stacktop: .word stack+64*8
/*设置内存空间,进行寄存器数据的备份,从而解决寄存器的长时间占用*/
mymem: .space 64

简化版:

.global u_add
.globl _start
_start: 
	b	reset
	ldr	pc, _undefined_instruction
	ldr	pc, _software_interrupt
	ldr	pc, _prefetch_abort
	ldr	pc, _data_abort
	ldr	pc, _not_used
	ldr	pc, _irq
	ldr	pc, _fiq
_undefined_instruction: .word _undefined_instruction
_software_interrupt:	.word swi_handler
_prefetch_abort:	.word _prefetch_abort
_data_abort:		.word _data_abort
_not_used:		.word _not_used
_irq:			.word _irq
_fiq:			.word _fiq

reset:
	/* 设置cpu模式为SVC模式 */
	mrs	r0, cpsr
	bic	r0, r0, #0x1f  
	orr	r0, r0, #0xd3 
	msr	cpsr,r0

	/* 设置异常向量表起始地址 */
	ldr	r0, =_start
	mcr	p15, 0, r0, c12, c0, 0	@Set VBAR

    /*用户需要设置的初始化*/
    ldr sp, stacktop  /*设置svc sp*/
    sub r6, sp , #64  /*计算user需要指向的栈顶地址*/

    /*切换到用户模式*/
	mrs	r0, cpsr
	bic	r0, r0, #0x1f  
	orr	r0, r0, #0x10 
	msr	cpsr,r0

    mov sp, r6  /*设置user sp*/

    /*跳转到应用程序*/
    bl	_main


_main:
    mov r0, #3
    mov r1, #4
    bl u_add
    mov r3, r0
    nop
    nop
loop:
    b loop 

u_add:
    stmfd sp!, {lr}
    swi 0     /*产生软中断异常*/
    ldmfd sp!, {pc}

sys_add:
    stmfd sp!, {lr}
    add r0,r0,r1
    ldmfd sp!, {pc}


/*swi 异常处理函数  处于svc模式*/
swi_handler:
    stmfd sp!, {r1-r12,lr}
    /*区分中断*/
    /*调用真正的加法函数*/
    bl sys_add 
    ldmfd sp!, {r1-r12,pc}^

stack: .space 64*8
stacktop: .word stack+64*8

 4:体验汇编到c的转换

//test.lds:链接文件,后缀一般为.lds
/*ENTRY:程序的入口地址,可重新指定,不过不建议*/
ENTRY(_start)
SECTIONS{
	. = 0x0;    /*代码段text是从0开始的*/
	.text : {
		start.o(.text)  /*可以指定顺序,如果不指定机器根据自己的安排进行各种.o文件的链接,这里注意:后一个链接的文件需要前一个文件链接过后的文件则需要指定顺序*/
		*(.text)
	}
	.data : {
		*(.data)    /*数据段,比如初始化的全局变量a的值等等*/
	}
	.bss : {
		*(.bss)	    /*未初始化*/
	}
}
//makefile文件,类似最上面终端1的shell脚本,值得注意的是需要将-Ttext=0x0改为-Ttest.lds,勾连链接文件
all:
	arm-linux-gcc myadd.S -o start.o -c -g
	arm-linux-gcc main.c -o main.o -c -g
	#-Ttext=0x0:是因为我们安装的虚拟单片机text地址是从0开始的
	#如果是真实的单片机,那么会改,如 -Ttext=0x100等
	#-Ttest.lds 包含 -Ttext=0x0
	arm-linux-ld  start.o main.o -o start.elf -Ttest.lds
//gdbS.sh文件
#!/bin/bash
qemu-system-arm -machine xilinx-zynq-a9 -m 256M -serial stdio -kernel start.elf -S -s
/*myadd.S文件*/
.global u_add
.globl _start
_start: 
	b	reset
	ldr	pc, _undefined_instruction
	ldr	pc, _software_interrupt
	ldr	pc, _prefetch_abort
	ldr	pc, _data_abort
	ldr	pc, _not_used
	ldr	pc, _irq
	ldr	pc, _fiq
_undefined_instruction: .word _undefined_instruction
_software_interrupt:	.word swi_handler
_prefetch_abort:	.word _prefetch_abort
_data_abort:		.word _data_abort
_not_used:		.word _not_used
_irq:			.word _irq
_fiq:			.word _fiq

reset:
	/* 设置cpu模式为SVC模式 */
	mrs	r0, cpsr
	bic	r0, r0, #0x1f  
	orr	r0, r0, #0xd3 
	msr	cpsr,r0

	/* 设置异常向量表起始地址 */
	ldr	r0, =_start
	mcr	p15, 0, r0, c12, c0, 0	@Set VBAR

    /*用户需要设置的初始化*/
    ldr sp, stacktop  /*设置svc sp*/
    sub r6, sp , #64  /*计算user需要指向的栈顶地址*/

    /*切换到用户模式*/
	mrs	r0, cpsr
	bic	r0, r0, #0x1f  
	orr	r0, r0, #0x10 
	msr	cpsr,r0

    mov sp, r6  /*设置user sp*/

    /*跳转到应用程序*/
    bl	main        /*将_main改为main*/

/*将mian转到c文件中,用c文件来编写之前汇编编写的mian函数*/

u_add:
    stmfd sp!, {lr}
/*
  机器自己做:
  汇编的寄存器r0,r1,r2,r3接收参数
  最多4个,多个压栈重用寄存器
  我们需要管返回值	
@c--->r0,然后将值返回给c语言
 */
    @a-->r0  b--->r1 
    ldr r3, =buf 
    str r0, [r3]
    str r1, [r3,#4]
    mov r0, #0x11   //举例:r0可重用
    mov r1, #0x22   //如上
    swi 0     /*产生软中断异常*/
    @c--->r0
    ldr r3, =buf
    ldr r0, [r3,#8] /*取返回值*/
    ldmfd sp!, {pc}

sys_add:
    stmfd sp!, {lr}
    ldr r3, =buf
    ldr r0, [r3]
    ldr r1, [r3,#4]
    add r0,r0,r1
    str r0, [r3,#8]
    mov r0, #0x55
    ldmfd sp!, {pc}


/*swi 异常处理函数  处于svc模式*/
swi_handler:
    stmfd sp!, {r0-r12,lr}
    /*区分中断*/
    /*调用真正的加法函数*/
    bl sys_add 
    ldmfd sp!, {r0-r12,pc}^

buf: .space 64
stack: .space 64*8
stacktop: .word stack+64*8
//main.c
//由于是裸机编程,所以并不包含C库,如使用printf等等
int u_add(int a, int b);
//int u_sub(int a, int b);

int main()
{
    int a = 3;
    int b = 4;
    int c = 0;
    c = u_add(a,b);
    //c = u_sub(a,b);
    b = 5;
    while(1);
    return 0;    
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值