菜逼 - 2019年9月
type: channel
link: https://blog.chaol.top/2019/09/
items: x86-64 汇编基础 ---- 记读 CS APP
items: ChromiumOS安装

x86-64 汇编基础 ---- 记读 CS APP
type: item
date: 2019-09-24T09:20:00+00:00
description: x86-64 汇编基础 ---- 记读 《CS: APP》 通常情况下, 使用现代的优化编译器产生的代码至少与一个熟练的汇编语言程序员手工编写的代码一样有效 1. 看懂汇编码 1). 汇编码的格式 · ATT格式 这是GCC/ OBJDUMP和其它一些工具的常用格式, 由AT&T公司命名 使用命令gcc -S <file.c>输出的汇编码就是这种格式. 一段示例代码如下所示: movl (%rdi), %eax imull %eax, %eax movl %eax, (%rdi) ret 在《CS: APP》一书中, 使用ATT格式书写汇编码, 因此, 无特殊说明时, 下文的所有汇编码也是ATT格式. · Intel格式 Intel和Microsoft的文档中经常会出现这种格式的代码, 它个ATT格式的代码有些许不同, 如下示例: mov eax, DWORD PTR [rdi] imul eax, eax mov DWORD PTR [rdi], eax ret 使用命令gcc -S -masm=intel <file.c>以输出这种格式的代码 Introduction to x64 Assembly | Intel® Software 注意, 上述代码中的源操作数和目的操作数的位置发生了变化, 因此在分析代码时应注意汇编码的格式问题. 使用GCC编译器输出的汇编码中, 以 "." 开头的行是 伪指令 , 可以适当忽略. 2) 数据格式 在C语言中, 变量具有其"数据类型", 但是汇编码中的"变量"没有此概念(或者说, 没有"变量"的概念). 但是C语言中数据类型的概念在汇编语言中必须有与其相对应的机制, 在x86-64汇编中, 控制指令操作数的长度, 与C语言中的数据类型概念对应. 下表是摘自书中的C语言数据类型在x86-64中的大小: C声明 Intel 数据类型 汇编代码后缀 大小(字节) char 字节 b 1 short 字 w 2 int 双字 l 4 long 四字 q 8 char * 四字 q 8 float 单精度 s 4 double 双精度 l 8 在汇编码(ATT格式)中, 通过在指令后加"后缀"表明操作数的大小. (后缀见上表) 3) 操作数指示符 几乎每一条指令都有对应的操作数, 操作数的值有几种形式: 立即数/ 寄存器/ 内存, 其中, 立即数和寄存器可以直接参与运算, 但存放于内存中的数参与运算时, 需要访存操作(此时立即数或寄存器中的值是内存地址). 最完整的一种地址形式是 Imm(r_a, r_i, s) , 它的运算后有效地址为 Imm + R[r_a] + R[r_i] \cdot s, 例如, 8(%rax, %rdx, 4). ATT格式汇编中的操作数格式如下表所述, 其中, R[r]表示从寄存器组中取出寄存器r的值; M[addr]表示从内存的地址addr处取值. 类型 格式 操作数值 名称 立即数 $Imm Imm 立即数寻址 寄存器 r R[r] 寄存器寻址 存储器 Imm M[Imm] 绝对寻址 存储器 (r) M[R[r]] 间接寻址 存储器 Imm(r) M[Imm+R[r]] (基址 + 偏移量)寻址 存储器 (rb, ri) M[R[rb] + R[ri]] 变址寻址 存储数 Imm(rb, ri) M[Imm + R[rb] + R[ri]] 变址寻址 存储器 (, ri, s) M[R[ri] * s] 比例变址寻址 存储器 Imm(, ri, s) M[Imm + R[ri] * s] 比例变址寻址 存储数 (ra, ri, s) M[R[ra] + R[ri] * s] 比例变址寻址 存储器 Imm(ra, ri, s) M[Imm + R[ra] + R[ri] * s] 比例变址寻址 应当注意, 取值(尤其是从内存中取值)时的数据长度由指令(后缀)决定. 2. 通用寄存器 x86-64中的寄存器比RISC架构的CPU的寄存器少. 一个x86-64的CPU包含一组16个存储64位值的通用目的寄存器. 它们的名字都已%r开头, 不过由于指令集的历史演化, 它们的命名还有一些不同. 下图所述为这16个寄存器: 63~0位 31~0位 15~0位 7~0位 用途 %rax %eax %ax %al 返回值 %rbx %ebx %bx %bl 被调用者保存 %rcx %ecx %cx %cl 第4个参数 %rdx %edx %dx %dl 第3个参数 %rsi %esi %si %sil 第2个参数 %rdi %edi %di %dil 第1个参数 %rbp %ebp %bp %bpl 被调用者保存 %rsp %esp %sp %spl 栈指针 %r8 %r8d…

ChromiumOS安装
type: item
date: 2019-09-20T05:29:00+00:00
description: 记一次FydeOS安装尝试和浅尝Linux操作系统安装 贴一个FydeOS链接, 该系统就是个贴牌Chromium OS. 官网安装方式在这里不做考虑. 偶然看到原来官方还给了这么个wiki 本次尝试安装目标: 硬盘安装 不刻盘 磁盘单分区 系统镜像分析 官网下载的FydeOS是一个img镜像. 分析官网提供的安装方式可以猜测, 该镜像可能是一个磁盘的RAW镜像. file命令可以基本确定其为磁盘的RAW镜像, 因此可以使用loopback方式尝试将其挂载. file命令输出 fydeos.img: DOS/MBR boot sector; partition 1 : ID=0xee, start-CHS (0x0,0,2), end-CHS (0x3ff,255,63), startsector 1, 10092700 sectors 首先将其设置为loop设备 losetup [options] -f | <loopdev> <file> 使用fdisk查看其分区布局(可能是我的操作方式有误, 使用parted时打印的分区布局是错误的) Device Start End Sectors Size Type /dev/loop0p1 5898240 10092652 4194413 2G Microsoft bas /dev/loop0p2 20480 53247 32768 16M ChromeOS kern /dev/loop0p3 319488 5898239 5578752 2.7G ChromeOS root /dev/loop0p4 53248 86015 32768 16M ChromeOS kern /dev/loop0p5 315392 319487 4096 2M ChromeOS root /dev/loop0p6 16448 16448 1 512B ChromeOS kern /dev/loop0p7 16449 16449 1 512B ChromeOS root /dev/loop0p8 86016 118783 32768 16M Microsoft bas /dev/loop0p9 16450 16450 1 512B ChromeOS rese /dev/loop0p10 16451 16451 1 512B ChromeOS rese /dev/loop0p11 64 16447 16384 8M unknown /dev/loop0p12 249856 315391 65536 32M EFI System 有了这个分区布局, 就可以尝试挂载了. 当然也可以使用dd把各分区单独分出来. 我是使用了losetup配合偏移量将各分区分别设置为loopback设备, 再使用mount将其一一挂载的; 有其他挂载方式请随意. 其实通过虚拟机运行FydeOS可以发现, 能用到的分区其实只有root/ stateful/ efi三个分区. (FydeOS可以切换到tty的), 因此上述多个分区其实是没有必要的. 猜测可能是Google对旗下ChromeBook设置的保留分区. 在这里补一个Google里搜索到的ChromiumOS安装教程 启动引导分析 挂载EFI分区, 查看grub.cfg内容, 关键启动记录如下示 menuentry "Boot FydeOS image A with Intel graphics chip" { linux /syslinux/vmlinuz.A init=/sbin/init boot=local rootwait ro noresume noswap loglevel=7 noinitrd console= i915.modeset=1 nouveau.modeset=0 radeon.modeset=0 amdgpu.modeset=0 cros_efi cros_debug root=PARTUUID=1687817B-70DD-E64B-AA45-82566DA0EB8D } 到此基本上可以尝试安装了. 将上述提及到的三个分区在硬盘里安置好, 然后从grub.cfg中指定根文件分区的分区ID即可开机了. *查看分区ID: lsblk [选项] [<设备> ...] LVM支持 是的, 使用LVM真的是没事找事. 主要是想实现单硬盘分区, 不想为了一个ChromiumOS而把硬盘分区表弄得乱糟糟的. 由于在开机时内核(vmlinuz)不能识别LVM分区, 因此需要设法将LVM分区在内核启动过程中挂载. (据说现在新版内核已经可以直接挂载LVM分区了, 不过FydeOS这个貌似是不行的) 有两种方案: initramfs 使用内核的device-mapp…