读《Professional Assembly Language》之lc消失之迷

Professional Assembly Lanauge

Professional Assembly Lanauge

今年是离开校园的第五年,这五年来我一直在从事应用软件的设计、开发工作,大部分时间是在与高级编程语言、设计模式、业务逻辑打交道。它们大多流于表面,久而久之,与技术底层疏远了,诸如计算机组成原理、汇编语言、编译原理、数据结构以及算法慢慢得生疏,时至今日,我已经弄不懂IA-32里有几类寄存器、间接寻址、词法分析是怎么一回事情了。五年是一个契机,趁着下一个五年开始之际,我计划用三个月至半年时想间,重新学习这些知识,以期达到巩固基础,厚积薄发的目的。

学习过程肯定会有问题,找不出问题的学生不是好学生。因此,我把遇到的问题和解决的方法记录下来,便形成了读书笔记。本篇博文便是我在阅读《Professional Assembly Language》一书时,所作的其中一篇读书笔记。《Professional Assembly Language》,中文译作《汇编语言程序设计》,是我学习汇编语言时选择的工具书,该书对于我这种已经有了高级语言的使用经验,又热衷Linux的人来说非常合适。

上文里说到了,在x86-64的机器上,通过对as命令加入–32 参数,并在 ld 命令里加入-melf_i386参数,即可编译并链接成32-bit的cpuid。关于这两个参数的说明,可以参看man手册。

同样是在第四章节,链接c库函数,作者提供了另一个版本的cpuid,这次链接过程出现了新问题,可不是简单加入个参数就能解决的。是什么问题呢?如下:
$ as -gstabs --32 -o cpuid2.o cpuid2.s
$ ld -melf_i386 -dynamic-linker /lib/ld-linux.so.2 -o cpuid2 -lc cpuid2.o
ld: skipping incompatible /usr/lib/libc.so when searching for -lc
ld: skipping incompatible /usr/lib/libc.a when searching for -lc
ld: cannot find -lc

如果在ld命令加入–verbose参数,则更能看清问题:
attempt to open /usr/x86_64-linux-gnu/lib32/libc.so failed
attempt to open /usr/x86_64-linux-gnu/lib32/libc.a failed
attempt to open /usr/i386-linux-gnu/lib32/libc.so failed
attempt to open /usr/i386-linux-gnu/lib32/libc.a failed
attempt to open /usr/local/lib32/libc.so failed
attempt to open /usr/local/lib32/libc.a failed
attempt to open /lib32/libc.so failed
attempt to open /lib32/libc.a failed
attempt to open /usr/lib32/libc.so failed
attempt to open /usr/lib32/libc.a failed
attempt to open /usr/i386-linux-gnu/lib/libc.so failed
attempt to open /usr/i386-linux-gnu/lib/libc.a failed
attempt to open /usr/local/lib/libc.so failed
attempt to open /usr/local/lib/libc.a failed
attempt to open /lib/libc.so failed
attempt to open /lib/libc.a failed
attempt to open /usr/lib/libc.so succeeded
opened script file /usr/lib/libc.so
ld: skipping incompatible /usr/lib/libc.so when searching for -lc
attempt to open /usr/lib/libc.a succeeded
ld: skipping incompatible /usr/lib/libc.a when searching for -lc
ld: cannot find -lc

很明显,找不到libc.so文件,可是检查了/lib目录,发现存在libc的踪影,不过它是64-bit的,因此导致了上述的incompatible的信息。
$ file /lib/libc-2.11.2.so
/lib/libc-2.11.2.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped

要解决这个问题,需要安装一个package,这就是ia32-libs,以下是说明:

This package contains runtime libraries for the ia32/i386 architecture, configured for use on an amd64 or ia64 Debian system running a 64-bit kernel.

IA32-libs in Aptitude

IA32-libs in Aptitude

不同的Linux发行版的安装方法不同,这里就不赘述了。安装之后,再次执行ld,这次需要特别注意使用32-bit的库文件。
$ ld /lib32/libc.so.6 -melf_i386 -o cpuid2 cpuid2.o -dynamic-linker /lib32/ld-linux.so.2
$ ./cpuid2

The processor Vendor ID is ‘AuthenticAMD’

2 Comments

楼兰17 2 月, 2013 at 8:03 下午

不用装32位库啊,书上是u386的,直接在x64的机器上学不是更好么。

#cpuid2.s View the CPUID Vecdor ID string using C Library calls
.section .data
output:
.asciz “The processor Vender ID is ‘%s’n”

.section .bss
.lcomm buffer, 12

.section .text
.global _start
_start:
movl $0, %eax
cpuid
movl $buffer, %edi
movl %ebx, (%edi)
movl %edx, 4(%edi)
movl %ecx, 8(%edi)
pushq $buffer
pushq $output
call printf
addq $16, %rsp
pushq $0
call exit

编译指令:
as -g -o cpuid2.o cpuid2.s
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o cpuid2 -lc cpuid2.o

-所有的pushl入栈指令需要被替换成pushq,因为x64下地址为8字节的了
-call后的回栈addl $8, %esp因该被替换成addq $16, %rsp,原因同上

Xu Haojie17 2 月, 2013 at 9:19 下午

没错,这本书是围绕X86讲开的,但我想尝试下书本之外的内容,毕竟现在已经全是Intel® 64架构了。如果这本书能够更新到64位平台,那就再好不过了。

Leave a comment

Your comment