本篇文章介绍汇编,链接等常识,同时介绍了x86-64和armv8-a的一些指令语法
现代汇编学习
之前学的80x86
汇编太古老了,甚至连第一版linux kernel
代码都看不懂,现在整理一下一些汇编知识,主要是针对x86
和armv8-a
架构的,但是本文并不会教具体的指令长什么样,也不会阐述怎么写一个通用汇编代码。学习汇编本身不是我们的终极目的。我们的目的是为了更好开发软件或者高性能库,因此会介绍一下编译,链接的原理和流程。
汇编语言类型
-
AT&T
- 是这个实验室提出的一种语法,注意它和指令集是没关系的,仅仅是一种语法而已。
- 对于x86处理器,立即数由
$
,寄存器由%
引用。 - 对于arm处理器,直接使用arm官方的语言格式。
-
intel
- 本科会学到的一种语言格式,x86汇编
- 简单,易用
-
汇编器的作用是把汇编语言翻译成机器语言,所以不同的汇编语言可能会使用不同的汇编器。他们的机器语言即指令。
-
GAS 汇编器可以汇编x86的汇编语言,也可以汇编arm。
-
Intel assembler 只能汇编 intel的汇编语言,就像icc。
汇编器
汇编器列表
- AT&T assembler - as
- Borland’s Turbo Assembler - TASM
- GNU assembler - gas,GCC默认使用这个
- Intel Assembler
- Microsoft Assembler - MASM
- Netwide Assembler - NASM
- Yet Another Assembler - YASM
汇编器都干了什么
-
汇编器负责把当前源文件的所有变量,常量,宏,
label
解析等等并且生成相应的符号表(这时候的解析是初步的,符号表是不完整的,后续工作链接器会接手),所谓解析就是确定他们的地址。这些地址都是基于本模块计算出来的相对地址,绝对地址的计算需要到链接阶段才能做。 -
汇编器的输出是目标文件
Assembling:
- Assembling converts source program into object program if syntactically correct and
generates an intermediate .obj file or module.
- It calculates the offset address for every data item in data segment and every
instruction in code segment.
- A header is created which contains the incomplete address in front of the generated obj
module during the assembling.
- Assembler complains about the syntax error if any and does not generate the object
module.
- Assembler creates .obj .lst and .crf files and last two are optional files that can be
created at run time.
- For short programs, assembling can be done manually where the programmer translates
each mnemonic into the machine language using lookup table.
- Assembler reads each assembly instruction of a program as ASCII character and
translates them into respective machine code.
-
符号表实际上就是用于链接器定位每个目标文件的变量和函数信息比如汇编中重要的三个节
.bss .data .text
-
在汇编语言源代码可以调用外部文件的函数,就像C语言调用库函数一样。汇编器对这些函数或者变量无法进行地址计算。这些活由链接器干。
-
c 语言中 加了static的函数不会出现在 global section
-
目标文件的三种类型(来自CSAPP:chapter 7)
- Relocatable object file. Contains binary code and data in a form that can be combined with other relocatable object files at compile time to create an executable object file.
- Executable object file. Contains binary code and data in a form that can be copied directly into memory and executed.
- Shared object file. A special type of relocatable object file that can be loaded into memory and linked dynamically, at either load time or run time.
-
nm
工具可以查看某个目标文件的符号(readelf和objdump
都可以看符号表)-
nm -gD yourLib.so objdump -TC 也可以(C用于c++) readelf -Ws
-
-
一个简单的例子:
...
int x = 0;
int y = -1;
y = x;
...
上面这个片段定义了两个全局标号x y
,这两个标号实际上是一个地址,但是我们在C语言引用的时候实际上是引用值而不是地址。只有y = &x
这个语句的含义才是将x
这个标号的值(即x
的地址)赋给y
y = x
这个语句实际上会被编译成
mov eax,[x]
mov dword[y],eax
链接器
- 链接器负责进一步解析所有的符号,函数名,(根据每个目标文件的符号表)把所有的目标文件链接成一个最终的可执行文件。链接器收集所有目标文件的符号表信息,合并同类的段(比如不同目标文件的代码段,数据段)等工作。最终可执行文件的符号表是完整的。
- 比如两个.o文件都定义了函数
void foo()
,这时候链接器需要判断哪个是需要被采用的 - 在.o文件中没有在
global
中的函数是无法被其他.o文件调用的,实际上在汇编阶段不会出现在符号表,因此链接器也无法使用。(这些函数就是在c
中加了static
修饰符的变量)
- 比如两个.o文件都定义了函数
This involves the converting of .OBJ module into .EXE(executable) module i.e.
executable machine code.
- It completes the address left by the assembler.
Microprocessors lecture 5: Programming with 8086 Microprocessor
- It combines separately assembled object files.
- Linking creates .EXE, .LIB, .MAP files among which last two are optional files.
链接器负责把全部的符号解析成最终的地址。它负责解析所有的符号。
ld(链接器)
-
如果希望兼容32位的elf输出,这里需要使用
-m
选项ld -m elf_i386 -s -o file file.o
linker script
链接脚本是链接器使用的。脚本中会指定某些默认行为,比默认链接的一些标准库,比如可执行文件的入口地址。
加载器
- loader通常由shell进程负责唤起,它将可执行文件的代码加载到内存。
It Loads the program in memory for execution.
- It resolves remaining address.
- This process creates the program segment prefix (PSP) before loading.
- It executes to generate the result.
可执行文件格式
-
常用的有ELF:executable and linkable format
bin flat-form binary files (e.g. DOS .COM, .SYS) ith Intel hex srec Motorola S-records aout Linux a.out object files aoutb NetBSD/FreeBSD a.out object files coff COFF (i386) object files (e.g. DJGPP for DOS) elf32 ELF32 (i386) object files (e.g. Linux) elf64 ELF64 (x86_64) object files (e.g. Linux) elfx32 ELFX32 (x86_64) object files (e.g. Linux) as86 Linux as86 (bin86 version 0.3) object files obj MS-DOS 16-bit/32-bit OMF object files win32 Microsoft Win32 (i386) object files win64 Microsoft Win64 (x86-64) object files rdf Relocatable Dynamic Object File Format v2.0 ieee IEEE-695 (LADsoft variant) object file format macho32 NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X (i386) object files macho64 NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X (x86_64) object files dbg Trace of all info passed to output stage elf ELF (short name for ELF32) macho MACHO (short name for MACHO32) win WIN (short name for WIN32)
objconv 工具
objconv -fnasm main.o
把目标文件反汇编成指定格式的汇编语言
x86汇编
.set symbol,expression
,把符号设为具体的值
AT&T语法
- 指令可能会加后缀表示操作数的宽度
- “byte” refers to a one-byte integer (suffix b)
- “word” refers to a two-byte integer (suffix w),
- “doubleword” refers to a four-byte integer (suffix l), and
- “quadword” refers to an eight-byte value (suffix q).
- MOV:
movl,movw,movb,movq
.(32,16,8,64)一般如果没有后缀那就是默认的长度。
mov 基本指令
如果用到扩展,mov还会有s(signed),z(zero)的后缀,
movzbl %al,%ebx 表示对al寄存器(8-bit)进行zero扩展放到ebx(64-bit)
mov 内存寻址方式segment:displacement(base register, index register, scale factor)
即segment:[base register + displacement + index register * scale factor]
movzwl (%rdx,%rax,2),%edx
函数定义
.type start, @function
表示将符号start定义成一个函数标号
AVX,SSE指令
x64 寄存器
- There are sixteen 64-bit registers in x86-64: %rax, %rbx, %rcx, %rdx, %rdi, %rsi, %rbp, %