汇编语言程序设计读书笔记(2)- 相关工具64位系统篇

汇编语言程序设计一书,在32位系统下应该不会有什么问题,然而在64位系统下,则会有些不一样的地方。有些程序范例还会汇编错误或者执行错误。

博主所用系统为CentOS v6.4 x64。本文主要解决32位的汇编程序如何在64位环境下汇编、连接,而不论述64位汇编语言如何设计。

1. 64位系统下编译32位的C程序

以程序test5.c为例,程序代码很简单,如下:

test5.c


这个C源程序没有什么32位还是64位之说,用gcc编译后,在64位系统下就得到64位的elf文件,执行也不会有问题,如下图所示:

image_thumb3

上图用file test5很清楚的看到是64-bit的文件。

那么怎么编译成32位的程序呢?用-m32参数。会发现有错误,错误如下:

image_thumb

对于警告和exit不兼容,可以包含头文件stdlib.h就可以解决。

对于gnu/stubs-32.h:没有哪个文件或目录,需要安装glibc-devel和glibc-devel.i686。对于CentOS,安装命令为:yum install glibc-develyum install glibc-devel.i686

yum install glibc-devel,如下图

image_thumb4

yum install glibc-devel.i686,如下图:

image_thumb5

之后使用-m32编译,就不会再发生问题了。如下图:

image_thumb6

上图用file test5很清楚的看到是32-bit的文件。

总结以上主要有三点:

灯泡 64位系统下编译32位程序使用-m32参数,即gcc –m32 –o output_file input_file.c

灯泡 提示隐式声明与内建函数’exit’不兼容的警告,增加#include <stdlib.h>来解决

灯泡 gnu/stubs-32.h:没有哪个文件或目录的错误,需要安装glibc-devel和glibc-devel.i686来解决

 

2. 64位系统下汇编32位的汇编程序

1). 64位汇编和32位汇编不同

汇编语言64位和32位是很不一样的,这里提供一份Intel官方的对64位的汇编简单介绍的pdf文档下载: Introduction_to_x64_Assembly。虽然该文档按照微软的MASM的格式来说明的,但是还是可以得到一些我们需要的信息,从该文档中可以知道64位的寄存器已经和32位的不一样了,比如64位寄存器是rax,rbx等,低32位的才是使用eax,ebx。

对于系统调用,64位系统和32位系统大大不一样了,比如sys_write的系统调用,32位系统和64位系统分别如下:

32位的sys_write(stdout, str, length)的汇编调用

32位系统的sys_write(stdout, str, length)的汇编调用

 

64位的sys_write(stdout, str, length)的汇编调用

64位系统的sys_write(stdout, str, length)的汇编调用

 

虽然出于兼容性,32位系统的调用仍然可以在64位系统上运行,但两者已经大大不一样了。本文不是论述如何写64位汇编语言的,而是为了解决32位的汇编代码可以在64位环境下运行。

 

2). 64位系统下用as和ld汇编32位的汇编程序

那么怎样在64位系统中汇编32位的汇编程序呢?以以下例子cpuid2.s为例,代码为:

cpuid2.s

 

这个代码的具体实现,后续的章节会介绍。目前只知道是用于输出CPU厂商ID字符串的就行了。

在64位系统下,如果按照书中所述的那样as和ld,会产生错误,如下图:

image_thumb1[1]

说是push操作无效。

如果不修改源代码为64位的汇编,要解决这个问题,就需要命令64位系统按照32位的去汇编,as参数是--32, ld参数是-m elf_i386。如下图:

image_thumb2

file cpuid2可以看到确实是32位的文件,而且执行也没有问题。这里要特别对ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o cpuid2 -L/lib -lc cpuid2.o这行命令进行说明。

-m elf_i386:表示按照elf_i386的模块进行连接,即32位的。

-lc: 因为程序中调用了标准的C库函数printf和exit,因此需要连接C动态库libc.so,所以需要参数-lc来指定连接的库文件,一般而言libxxx.so采用-lxxx的参数。

-L/lib:博主的系统有多个libc.so,包括64位的,32位的,arm结构的,如下图所示,能搜出很多个libc.so。

image_thumb16

而/lib/libc.so才是32位x86系统所需要的动态库,所以使用-L/lib来指定库文件的路径,那么-L/lib –lc就指定了连接的是/lib/libc.so。

-dynamic-linker /lib/ld-linux.so.2:用于运行时动态加载libc.so动态库的。否则执行生成的可执行文件时会出错。

 

3). 64位系统下用gcc汇编32位的汇编程序

还是以上面的cpuid2.s为例,使用gcc -m32的参数进行汇编成32位的系统文件,特别的,这里由于没有main函数,而是用_start做入口点,因此需要使用参数 –nostdlib,如下图:

image_thumb1

gcc -nostdlib -m32 -o cpuid2 cpuid2.s -L/lib -lc进行说明。

-m32:按照32位的编译。

-nostdlib:如果没有这个参数,gcc会连接gnu库的函数,该函数会以_start为进入点,执行一段程序后,跳到main执行,而这个汇编源程序中用_start做进入点,而且没有main,因此,没有这个参数的话,会提示没有main定义以及重复定义_start的错误。加了这个参数后,则不会去连接gnu函数。

 

综上所述,64位系统下汇编32位汇编程序的做法是:

as --32 –o output_file.o input_file.s

ld –m elf_i386 –dynamic-linker /lib/ld-linux.so.2 –o output_file –L/path –llibname input_file.s

或者

gcc –m32 –nostdlib –o output_file –L/path –llibname input_file.s

posted on 2013-11-06 18:03  kenzhang1031  阅读(2583)  评论(3编辑  收藏  举报