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

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

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

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

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

test5.c#include <stdio.h>

int main()
{
	char str[4];
	str[0]=‘f‘;
	str[1]=‘g‘;
	str[2]=‘j‘;
	str[3] = 0;
	printf("CPU id is %s\n", str);
	exit(0);
}

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

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

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

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

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

yum install glibc-devel,如下图:

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

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

上图用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)的汇编调用# sys_write(stdout, str, length)的汇编调用
movl $4, %eax
movl $stdout,  %ebx
movl $str, %ecx
movl $length, %edx
int $0x80

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

64位系统的sys_write(stdout, str, length)的汇编调用# 64位的sys_write(stdout, str, length)的汇编调用
movq  $1, %rax
movq $stdout, %rdi
movq $str, %rsi
movq $length, %rdx
syscall

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

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

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

cpuid2.s# cpuid2.s file
.section .data
output:
    .asciz "CPUID is ‘%s‘\n"
.section .bss
    .lcomm buffer, 12
.section .text
.globl _start
_start:
    nop
    movl $0, %eax
    cpuid

    movl $buffer, %edi
    movl %ebx, (%edi)
    movl %edx, 4(%edi)
    movl %ecx, 8(%edi)

    pushl $buffer
    pushl $output
    call printf

    addl $8, %esp

    pushl $0
    call exit
	

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

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

说是push操作无效。

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

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。

而/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,如下图:

对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

时间: 2024-10-13 05:51:04

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

汇编语言程序设计读书笔记(3)- 程序范例

主要描述三方面的内容:第一是汇编语言的程序模版,以及模版涉及到的一些知识点:第二是如何调试汇编语言:第三是如何在汇编语言中调用C库函数. 1. 汇编语言的组成 汇编语言由段(section)组成,一个程序中执行的代码,叫文本段(text),程序还可能有定义变量,有付给初始值的变量放在数据段(data)中,没有赋初值或者付给零初值的放在bss段中.text段一定是要有的,data和bss可以没有. 2. 段的定义 用.section语法定义段.比如: .section .text定义文本段, .s

汇编语言程序设计读书笔记(1)- 相关工具

linux下汇编语言采用的是AT&T语法,可使用GNU工具,包括汇编器gas,连接器ld,编译器gcc,调试器gdb或kdbg,objdump的反汇编功能,简档器gprof.以简单的例子分别对每个工具在汇编语言开发中的用法进行简单说明. 这些工具都要在linux环境下使用,先建立linux的开发环境,可参考文章“windows7 64位系统安装VMware Centos 64位系统搭建开发环境”. 假设有以下简单的c程序test1.c. #include <stdio.h> int m

汇编语言程序设计读书笔记(4)- 程序设计基础之一

目录: 一.数据定义 1.变量数据定义 2.常量数据定义 3.缓冲区定义 二.寻址方式 1.立即数寻址 2.寄存器寻址 3.直接寻址 4.寄存器间接寻址 5.寄存器相对寻址 6.变址寻址 三.数据传送和mov指令 1.数据传送规则 2.mov指令 四.条件传送数据cmov指令 1.状态标志位 2.cmov指令 五.交换数据 1.xchg指令 2.bswap指令 3.xadd指令 4.cmpxchg指令 5.cmpxchg8b指令 六.堆栈 1.堆栈简介 2.入栈指令push 3.出栈指令pop

Hadoop2.2.0分布式环境配置笔记2-编译64位hadoop源码

11.配置hadoop分布式环境!  三台机器都需要这么配置 1).将/opt/modules/hadoop-2.2.0-src重命名  mv /opt/modules/hadoop-2.2.0-src/ /opt/modules/hadoop-2.2.0-src_x32_back 2).解压64位源码 tar -zxvf /opt/modules/hadoop-2.2.0-src_x32_back/hadoop-dist/target/hadoop-2.2.0.tar.gz -C /opt/m

Hadoop2.2.0分布式环境配置笔记1-编译64位hadoop源码

我的测试环境是三台机器 分别是 Hadoop-Yarn.Hark.Com 192.168.1.200 Hadoop-Slave1.Hark.Com 192.168.1.201 Hadoop.Slave2.Hark.Com 192.168.1.202 我为了自己能充分练习hadoop 64位源码编译,所以三台机器都进行了下边的配置 环境: vmware9+centos6.4+hadoop2.2.0 0.创建hadoop帐号,大部分操作都要使用hadoop帐号的 1.关闭窗口模式 使用root账号

win7 64位系统 PB连接oracle数据库出现“oracle library oci.dll could not be loaded”问题的解决方法

今天与大家分享一个自己的学习笔记,希望能给遇到同样问题的人带来帮助. 不知道大家在win7 64位系统下用 PB连接oracle数据库时,是否遇到过“oracle library oci.dll could not be loaded”问题. 今天,在win7 64位系统下用 PB连接oracle数据库时,一直出现上述错误,在百度上找了很久,都没有找到一个完整的解决方案,咨询了很多人,(他们都说是我的PB和oracle没装好,但我装的时候没出现任何问题,一切都很顺利,而且PB和oracle都能正

Windows7 64位系统搭建Cocos2d-x 2.2.1最新版以及Android交叉编译环境(具体教程)

原文地址:http://blog.csdn.net/sttyytw/article/details/17005263 声明:本教程在參考了下面博文,并经过自己的摸索后实际操作得出,本教程系本人原创,因为升级后的cocos2d-x有了一些变化,眼下的博文还没有关于Cocos2d-x 2.2.1最新版搭建Android交叉编译环境组建的说明,所以我这几天研究了一下,如今将详细的搭建方法分享出来,也给自己学习Cocos2d-x做个笔记. 參考博文: http://www.cnblogs.com/lhm

Windows7 64位系统搭建Cocos2d-x-2.2.1最新版以及Android交叉编译环境(详细教程)

Windows7 64位系统搭建Cocos2d-x-2.2.1最新版以及Android交叉编译环境(详细教程) 声明:本教程在参考了以下博文,并经过自己的摸索后实际操作得出,本教程系本人原创,由于升级后的cocos2d-x有了一些变化,目前的博文还没有关于Cocos2d-x 2.2.1最新版搭建Android交叉编译环境组建的说明,所以我这几天研究了一下,现在将具体的搭建方法分享出来,也给自己学习Cocos2d-x做个笔记. 参考博文: http://www.cnblogs.com/lhming

C# 32位程序在64位系统下注册表操作

在64位的Windows操作系统中,为了兼容32位程序的运行,64位的Windows操作系统采用重定向机制.目的是为了能让32位程序在64位的操作系统不仅能操作关键文件文夹和关键的注册表并且又要避免与64位程序冲突 相关资料请查看32位程序在64位系统下运行的重定向机制 下面是以获取操作系统安装密匙KEY的案例: using System; using System.Collections.Generic; using System.Linq; using System.Text; using