C语言及AT&T汇编格式改写《现代X86汇编语言程序设计》范例(九)

通过改写示范程序Ch02_05,重点掌握以下内容:1、C语言声明固定大小整数类型的方式;2、movzbl、movzwl、movsbp、movswq、movslq等零扩展和有符号扩展传送指令;3、gdb中查看“寄存器+偏移量”指向的内存地址中不同宽度的数值;4、利用gdb查看C语言变量与寄存器、内存地址之间数值传递情况,采用“寄存器+偏移量”的方式进行数值传递;5、反汇编。

本程序的目标为:设定8个变量a、b、c、d、e、f、g、h,其中a、e为1个字节,b、f为1个字,c、g为1个双字,d、h为1个四字。计算prod1=prod2=a*b*c*d*e*f*g*h,quo1=quo2=(a+b+c+d)/(e+f+g+h),rem1=rem2=(a+b+c+d)%(e+f+g+h)(%为求余数),prod1、quo1、rem1用C语言计算求出,prod2、quo2、rem2用汇编语言计算。

关于字节、字、双字、四字的位数、C语言定义、汇编指令表示的对应关系如下:

大小

中文表达

英文表达

c语言定义

汇编指令后缀

8bit

字节

byte

char、int8_t

b

16bit

word

short、int16_t

w

32bit

双字

double words

int、int32_t

l

64bit

四字

quad words

long

q


一、编辑c语言如下:

#include

#include /*此头文件用于指定固定大小变量*/

extern int64_t IntegerMul_(int8_t a,int16_t b,int32_t c,int64_t d,int8_t e,int16_t f,int32_t g,int64_t h); /*引入外部汇编变量IntegerMul_ */

extern uint64_t UnsignedDiv_(uint8_t a,uint16_t b,uint32_t c,uint64_t d,uint8_t e,uint16_t f,uint32_t g,uint64_t h,uint64_t* quo2,uint64_t* rem2); /*引入外部汇编变量UnsignedDiv_ */

void IntegerMul(void)

{

int8_t a=2;

int16_t b=-3;

int32_t c=8;

int64_t d=4;

int8_t e=3;

int16_t f=-7;

int32_t g=-5;

int64_t h=10;

printf("Results for IntegerMul a=%d b=%d c=%d d=%ld e=%d f=%d g=%d h=%ld ",a,b,c,d,e,f,g,h);

int64_t prod1=a*b*c*d*e*f*g*h; /*用c语言计算乘积*/

int64_t prod2=IntegerMul_(a,b,c,d,e,f,g,h); /*用汇编计算乘积*/

printf(" prod1=%ld prod2=%ld ",prod1,prod2);

}

void UnsignedIntegerDiv(void)

{

uint8_t a=12;

uint16_t b=17;

uint32_t c=71000000;

uint64_t d=90000000000;

uint8_t e=101;

uint16_t f=37;

uint32_t g=25;

uint64_t h=5;

uint64_t quo1,rem1;

uint64_t quo2;

uint64_t rem2;

int rc;

printf("Results for UnsignedIntegerDiv a=%u b=%u c=%u d=%lu e=%u f=%u g=%u h=%lu ",a,b,c,d,e,f,g,h);

quo1=(a+b+c+d)/(e+f+g+h); /*C语言计算商*/

rem1=(a+b+c+d)%(e+f+g+h); /*C语言计算余数*/

printf(" quo1=%lu ,rem1=%lu ",quo1,rem1);

rc=UnsignedDiv_(a,b,c,d,e,f,g,h,&quo2,&rem2); /*用汇编继续除法计算,并且返回是否正确计算的值*/

if(rc==0)

printf("警告:除数不能为0");

else

printf("quo2=%lu, rem2=%lu ",quo2,rem2);

}

int main(void)

{

IntegerMul();

UnsignedIntegerDiv();

return 0;

}

二、编辑汇编程序如下:(错误程序)

.text

.global IntegerMul_

.global UnsignedDiv_

IntegerMul_:

movsbq %dil,%rdi

movswq %si,%rsi

imul %rsi,%rdi

mov %rdi,%rax

movslq %edx,%rdx

imul %rcx,%rdx

imul %rdx,%rax

movsbq %r8b,%r8

movswq %r9w,%r9

imul %r9,%r8

imul %r8,%rax

movslq 0x38(%rsp),%rdx

imul 0x40(%rsp),%rdx

imul %rdx,%rax

ret


UnsignedDiv_:

movzbq %dil,%rdi

movzwq %si,%rsi

add %rsi,%rdi

mov %edx,%edx

add %rcx,%rdx

add %rdx,%rdi

mov %rdi,%rax

xor %rdx,%rdx

movzbq %r8b,%r8

movzwq %r9w,%r9

add %r9,%r8

mov 0x38(%rsp),%edi

mov 0x40(%rsp),%rsi

add %rsi,%rdi

add %rdi,%r8

jne DivOK

xor %rax,%rax

jmp Done


DivOK:

p %r8

mov 0x48(%rsp),%rcx

mov %rax,(%rcx)

mov 0x50(%rsp),%rcx

mov %rdx,(%rcx)

mov $0x1,%rax


Done:

ret

三、编辑Makefile文件

ch02_05_0102:ch02_05_01.c ch02_05_02.o

gcc -g ch02_05_01.c ch02_05_02.o -o ch02_05_0102

ch02_05_02.o:ch02_05_02.asm

as ch02_05_02.asm -o ch02_05_02.o

四、编译、反汇编、gdb调试

编译后程序运行产生错误答案。利用反汇编可以查看完整的汇编程序。

$touch ch02_05_dump 创建ch02_05_dump空白文件

$objdump -d ./ch02_05_0102 >> ch02_05_dump 反汇编,并将反汇编的汇编程序传送到ch02_05_dump文件内。

查看反汇编文件,主要内容如下:

1、C语言IntegerMul函数代码:

401122: 55 push %rbp

401123: 48 89 e5 mov %rsp,%rbp

401126: 48 83 ec 30 sub $0x30,%rsp

40112a: c6 45 ff 02 movb $0x2,-0x1(%rbp)

40112e: 66 c7 45 fc fd ff movw $0xfffd,-0x4(%rbp)

401134: c7 45 f8 08 00 00 00 movl $0x8,-0x8(%rbp)

40113b: 48 c7 45 f0 04 00 00 movq $0x4,-0x10(%rbp)

401142: 00

401143: c6 45 ef 03 movb $0x3,-0x11(%rbp)

401147: 66 c7 45 ec f9 ff movw $0xfff9,-0x14(%rbp)

40114d: c7 45 e8 fb ff ff ff movl $0xfffffffb,-0x18(%rbp)

401154: 48 c7 45 e0 0a 00 00 movq $0xa,-0x20(%rbp)

40115b: 00

40115c: 0f bf 75 ec movswl -0x14(%rbp),%esi

401160: 44 0f be 4d ef movsbl -0x11(%rbp),%r9d

401165: 0f bf 55 fc movswl -0x4(%rbp),%edx

401169: 0f be 45 ff movsbl -0x1(%rbp),%eax

40116d: 4c 8b 45 f0 mov -0x10(%rbp),%r8

401171: 8b 4d f8 mov -0x8(%rbp),%ecx

401174: 48 83 ec 08 sub $0x8,%rsp

401178: ff 75 e0 pushq -0x20(%rbp)

40117b: 8b 7d e8 mov -0x18(%rbp),%edi

40117e: 57 push %rdi

40117f: 56 push %rsi

401180: 89 c6 mov %eax,%esi

401182: 48 8d 3d 7f 0e 00 00 lea 0xe7f(%rip),%rdi # 402008 <_IO_stdin_used+0x8>

401189: b8 00 00 00 00 mov $0x0,%eax

40118e: e8 9d fe ff ff callq 401030

401193: 48 83 c4 20 add $0x20,%rsp

401197: 0f be 55 ff movsbl -0x1(%rbp),%edx

40119b: 0f bf 45 fc movswl -0x4(%rbp),%eax

40119f: 0f af c2 imul %edx,%eax

4011a2: 0f af 45 f8 imul -0x8(%rbp),%eax

4011a6: 48 98 cltq

4011a8: 48 0f af 45 f0 imul -0x10(%rbp),%rax

4011ad: 48 89 c2 mov %rax,%rdx

4011b0: 48 0f be 45 ef movsbq -0x11(%rbp),%rax

4011b5: 48 0f af d0 imul %rax,%rdx

4011b9: 48 0f bf 45 ec movswq -0x14(%rbp),%rax

4011be: 48 0f af d0 imul %rax,%rdx

4011c2: 8b 45 e8 mov -0x18(%rbp),%eax

4011c5: 48 98 cltq

4011c7: 48 0f af c2 imul %rdx,%rax

4011cb: 48 8b 55 e0 mov -0x20(%rbp),%rdx

4011cf: 48 0f af c2 imul %rdx,%rax

4011d3: 48 89 45 d8 mov %rax,-0x28(%rbp)

4011d7: 44 0f bf 4d ec movswl -0x14(%rbp),%r9d

4011dc: 44 0f be 45 ef movsbl -0x11(%rbp),%r8d

4011e1: 0f bf 75 fc movswl -0x4(%rbp),%esi

4011e5: 0f be 45 ff movsbl -0x1(%rbp),%eax

4011e9: 48 8b 4d f0 mov -0x10(%rbp),%rcx

4011ed: 8b 55 f8 mov -0x8(%rbp),%edx

4011f0: ff 75 e0 pushq -0x20(%rbp)

4011f3: 8b 7d e8 mov -0x18(%rbp),%edi

4011f6: 57 push %rdi

4011f7: 89 c7 mov %eax,%edi

4011f9: e8 c4 01 00 00 callq 4013c2

4011fe: 48 83 c4 10 add $0x10,%rsp

401202: 48 89 45 d0 mov %rax,-0x30(%rbp)

401206: 48 8b 55 d0 mov -0x30(%rbp),%rdx

40120a: 48 8b 45 d8 mov -0x28(%rbp),%rax

40120e: 48 89 c6 mov %rax,%rsi

401211: 48 8d 3d 3b 0e 00 00 lea 0xe3b(%rip),%rdi # 402053 <_IO_stdin_used+0x53>

401218: b8 00 00 00 00 mov $0x0,%eax

40121d: e8 0e fe ff ff callq 401030

401222: 90 nop

401223: c9 leaveq

401224: c3 retq

2、C语言UnsignedIntegerDiv函数代码如下:

401225: 55 push %rbp

401226: 48 89 e5 mov %rsp,%rbp

401229: 48 83 ec 50 sub $0x50,%rsp

40122d: c6 45 ff 0c movb $0xc,-0x1(%rbp)

401231: 66 c7 45 fc 11 00 movw $0x11,-0x4(%rbp)

401237: c7 45 f8 c0 5f 3b 04 movl $0x43b5fc0,-0x8(%rbp)

40123e: 48 b8 00 04 6b f4 14 movabs $0x14f46b0400,%rax

401245: 00 00 00

401248: 48 89 45 f0 mov %rax,-0x10(%rbp)

40124c: c6 45 ef 65 movb $0x65,-0x11(%rbp)

401250: 66 c7 45 ec 25 00 movw $0x25,-0x14(%rbp)

401256: c7 45 e8 19 00 00 00 movl $0x19,-0x18(%rbp)

40125d: 48 c7 45 e0 05 00 00 movq $0x5,-0x20(%rbp)

401264: 00

401265: 0f b7 75 ec movzwl -0x14(%rbp),%esi

401269: 44 0f b6 4d ef movzbl -0x11(%rbp),%r9d

40126e: 0f b7 55 fc movzwl -0x4(%rbp),%edx

401272: 0f b6 45 ff movzbl -0x1(%rbp),%eax

401276: 4c 8b 45 f0 mov -0x10(%rbp),%r8

40127a: 8b 4d f8 mov -0x8(%rbp),%ecx

40127d: 48 83 ec 08 sub $0x8,%rsp

401281: ff 75 e0 pushq -0x20(%rbp)

401284: 8b 7d e8 mov -0x18(%rbp),%edi

401287: 57 push %rdi

401288: 56 push %rsi

401289: 89 c6 mov %eax,%esi

40128b: 48 8d 3d de 0d 00 00 lea 0xdde(%rip),%rdi # 402070 <_IO_stdin_used+0x70>

401292: b8 00 00 00 00 mov $0x0,%eax

401297: e8 94 fd ff ff callq 401030

40129c: 48 83 c4 20 add $0x20,%rsp

4012a0: 0f b6 55 ff movzbl -0x1(%rbp),%edx

4012a4: 0f b7 45 fc movzwl -0x4(%rbp),%eax

4012a8: 01 d0 add %edx,%eax

4012aa: 89 c2 mov %eax,%edx

4012ac: 8b 45 f8 mov -0x8(%rbp),%eax

4012af: 01 d0 add %edx,%eax

4012b1: 89 c2 mov %eax,%edx

4012b3: 48 8b 45 f0 mov -0x10(%rbp),%rax

4012b7: 48 01 d0 add %rdx,%rax

4012ba: 0f b6 4d ef movzbl -0x11(%rbp),%ecx

4012be: 0f b7 55 ec movzwl -0x14(%rbp),%edx

4012c2: 01 ca add %ecx,%edx

4012c4: 89 d1 mov %edx,%ecx

4012c6: 8b 55 e8 mov -0x18(%rbp),%edx

4012c9: 01 ca add %ecx,%edx

4012cb: 89 d1 mov %edx,%ecx

4012cd: 48 8b 55 e0 mov -0x20(%rbp),%rdx

4012d1: 48 8d 34 0a lea (%rdx,%rcx,1),%rsi

4012d5: ba 00 00 00 00 mov $0x0,%edx

4012da: 48 f7 f6 p %rsi

4012dd: 48 89 45 d8 mov %rax,-0x28(%rbp)

4012e1: 0f b6 55 ff movzbl -0x1(%rbp),%edx

4012e5: 0f b7 45 fc movzwl -0x4(%rbp),%eax

4012e9: 01 d0 add %edx,%eax

4012eb: 89 c2 mov %eax,%edx

4012ed: 8b 45 f8 mov -0x8(%rbp),%eax

4012f0: 01 d0 add %edx,%eax

4012f2: 89 c2 mov %eax,%edx

4012f4: 48 8b 45 f0 mov -0x10(%rbp),%rax

4012f8: 48 01 d0 add %rdx,%rax

4012fb: 0f b6 4d ef movzbl -0x11(%rbp),%ecx

4012ff: 0f b7 55 ec movzwl -0x14(%rbp),%edx

401303: 01 ca add %ecx,%edx

401305: 89 d1 mov %edx,%ecx

401307: 8b 55 e8 mov -0x18(%rbp),%edx

40130a: 01 ca add %ecx,%edx

40130c: 89 d1 mov %edx,%ecx

40130e: 48 8b 55 e0 mov -0x20(%rbp),%rdx

401312: 48 01 d1 add %rdx,%rcx

401315: ba 00 00 00 00 mov $0x0,%edx

40131a: 48 f7 f1 p %rcx

40131d: 48 89 55 d0 mov %rdx,-0x30(%rbp)

401321: 48 8b 55 d0 mov -0x30(%rbp),%rdx

401325: 48 8b 45 d8 mov -0x28(%rbp),%rax

401329: 48 89 c6 mov %rax,%rsi

40132c: 48 8d 3d 8e 0d 00 00 lea 0xd8e(%rip),%rdi # 4020c1 <_IO_stdin_used+0xc1>

401333: b8 00 00 00 00 mov $0x0,%eax

401338: e8 f3 fc ff ff callq 401030

40133d: 44 0f b7 4d ec movzwl -0x14(%rbp),%r9d

401342: 44 0f b6 45 ef movzbl -0x11(%rbp),%r8d

401347: 0f b7 75 fc movzwl -0x4(%rbp),%esi

40134b: 0f b6 45 ff movzbl -0x1(%rbp),%eax

40134f: 48 8b 4d f0 mov -0x10(%rbp),%rcx

401353: 8b 55 f8 mov -0x8(%rbp),%edx

401356: 48 8d 7d b8 lea -0x48(%rbp),%rdi

40135a: 57 push %rdi

40135b: 48 8d 7d c0 lea -0x40(%rbp),%rdi

40135f: 57 push %rdi

401360: ff 75 e0 pushq -0x20(%rbp)

401363: 8b 7d e8 mov -0x18(%rbp),%edi

401366: 57 push %rdi

401367: 89 c7 mov %eax,%edi

401369: e8 92 00 00 00 callq 401400

40136e: 48 83 c4 20 add $0x20,%rsp

401372: 89 45 cc mov %eax,-0x34(%rbp)

401375: 83 7d cc 00 cmpl $0x0,-0x34(%rbp)

401379: 75 13 jne 40138e

40137b: 48 8d 3d 54 0d 00 00 lea 0xd54(%rip),%rdi # 4020d6 <_IO_stdin_used+0xd6>

401382: b8 00 00 00 00 mov $0x0,%eax

401387: e8 a4 fc ff ff callq 401030

40138c: eb 1c jmp 4013aa

40138e: 48 8b 55 b8 mov -0x48(%rbp),%rdx

401392: 48 8b 45 c0 mov -0x40(%rbp),%rax

401396: 48 89 c6 mov %rax,%rsi

401399: 48 8d 3d 50 0d 00 00 lea 0xd50(%rip),%rdi # 4020f0 <_IO_stdin_used+0xf0>

4013a0: b8 00 00 00 00 mov $0x0,%eax

4013a5: e8 86 fc ff ff callq 401030

4013aa: 90 nop

4013ab: c9 leaveq

4013ac: c3 retq

3、分析代码:

(1)IntegerMul函数中40112a-401154,UnsignedIntegerDiv函数中40112d-40125d的代码说明两个函数都把a-h变量的值分别传递给-0x1(%rbp)、-0x4(%rbp)、-0x8(%rbp)、-0x10(%rbp)、-0x11(%rbp)、-0x14(%rbp)、-0x18(%rbp)、-0x20(%rbp)指向的内存空间内。

(2)用gdb查看各内存空间的值。

$gdb ./ch02_05_0102

(gdb)break IntegerMul 在IntegerMul函数处打断

(gdb)run 运行程序,到IntegerMul函数入口处中断

(gdb)display /d *(char *)($rbp-0x1) 显示第1个变量。/d表示显示十进制数。*(char *)表示按字节长度显示内存地址内的值,($rbp-0x1)表示寄存器rbp偏移-0x1的内存位置。注意gdb中寄存器前缀与汇编语言不同,gdb中寄存器前缀用$表示,汇编语言中用%表示。

(gdb)display /d *(short *)($rbp-0x4) 显示第2个变量,short表示按字的长度

(gdb)display /d *(int *)($rbp-0x8) 显示第3个变量,int表示按双字的长度

(gdb)display /d *(long *)($rbp-0x10) 显示第4个变量,long表示按四字的长度。第5-8个变量按类似方式操作。

(gdb)si 执行下一步,随着一步步调试执行,可以观察内存值的变化。

(3)汇编函数UnsignedDiv_还要传递商值和余数值到C语言中,在C语言反汇编UnsignedIntegerDiv代码第401356-40135b中

401356: 48 8d 7d b8 lea -0x48(%rbp),%rdi

40135a: 57 push %rdi

40135b: 48 8d 7d c0 lea -0x40(%rbp),%rdi

可知商值和余数值分别传递到-0x40(%rbp)、-0x48(%rbp)空间内。lea指令表示传递有效地址。

四、修改汇编程序

根据上述分析,修改汇编程序如下:

.text

.global IntegerMul_ /*定义用于有符号乘法计算的函数*/

.global UnsignedDiv_ /*定义用于无符号除法计算的函数*/

IntegerMul_:

movsbq -0x1(%rbp),%rdi /*movsbq指令表示将8位字节按有符号扩展到64位四字,其中dil是rdi低8位寄存器*/

movswq -0x4(%rbp),%rsi /*movswq指令表示将16位字按有符号扩展到64位四字,其中si是rsi低16位寄存器*/

imulq %rsi,%rdi /*rdi=a*b*/

movq %rdi,%rax /*rax=a*b */

movslq -0x8(%rbp),%rdx /*movslq指令表示将32位双字按有符号扩展到64位四字*/

imulq -0x10(%rbp),%rdx /*rdx=c*d*/

imulq %rdx,%rax /*rax=a*b*c*d*/

movsbq -0x11(%rbp),%r8 /*r8=e*/

movswq -0x14(%rbp),%r9 /*r9=f*/

imulq %r9,%r8 /*r8=e*f */

imulq %r8,%rax /*rax=a*b*c*d*e*f */

movslq -0x18(%rbp),%rdx /*rdx=g*/

imulq -0x20(%rbp),%rdx /*rdx=g*h*/

imulq %rdx,%rax /*rax=a*b*c*d*e*f*g*h */

ret



UnsignedDiv_:

addq %rsi,%rdi /*rdi=a+b */

addq %rdx,%rdi /*rdi=a+b+c */

addq %rcx,%rdi /*rdi=a+b+c+d */

movq %rdi,%rax /*rax=a+b+c+d */

xor %rdx,%rdx /*被除数为rdx:rax,将高位的rdx清零*/


addq %r9,%r8 /*r8=e+f */

mov -0x18(%rbp),%edi /*edi=g*/

mov %edi,%edi /*将edi扩展为64位*/

addq %rdi,%r8 /*r8=e+f+g */

mov -0x20(%rbp),%edi

mov %edi,%edi

addq %rdi,%r8 /*r8=e+f+g+h */

jnz DivOK /*当被除数r8不为0时,除法计算有效,跳转到DivOK执行除法计算,否则计算无效*/


xor %rax,%rax /*rax清零,除法计算无效时返回值为0*/

jmp Done


DivOK:

pq %r8 /*rdx:rax/r8,商保存在rax,余数保存在rdx*/

movq %rax,-0x40(%rbp) /*商传递到-0x40(%rbp)地址内,该地址传递给变量quo2*/

movq %rdx,-0x48(%rbp) /*余数传递到-0x48(%rbp)地址内,该地址传递给变量rem2*/

movq $1,%rax /*除法计算有效时,返回值为1*/

Done:

ret


最后经编译运行结果正确,运行结果如下:

Results for IntegerMul

a=2 b=-3 c=8 d=4 e=3 f=-7 g=-5 h=10

prod1=-201600

prod2=-201600

Results for UnsignedIntegerDiv

a=12 b=17 c=71000000 d=90000000000 e=101 f=37 g=25 h=5

quo1=536136904 ,rem1=157

quo2=536136904, rem2=157

展开阅读全文

页面更新:2024-02-28

标签:汇编程序   语言   余数   除法   寄存器   范例   变量   指令   函数   符号   格式   地址   语言程序设计

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top