ffutop

Preprocessor Output

2018-09-08

最近重新开始回顾 C 语言以及其编译后的文件格式 ELF。 暂时告别一步到位的命令 gcc main.c,如果从 .c 文件的编译来说,主要分为预编译(preprocess)、编译(Compilation)、汇编(Assembly)、链接(Linking) 四个步骤。 但是,仅仅从第一个流程 预编译 而言,就已经遇到了一些麻烦。

program.i

# 1 "program.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "program.c"
# 1 "header.h" 1
char *test(void);
# 2 "program.c" 2

int main(void)
{
}

预编译后的问题出现了诸如 # 1 "program.c"注释?

这里简单记录预处理输出文件的基本格式,方便今后回顾。

阅读更多


理解 Linux Kernel (2) - 多任务切换

2018-08-26

概述

《只是为了好玩》一书中,林纳斯描述过他最早的试验性程序就是让 CPU 执行两个不同的任务(一个不断输出A,另一个输出B),同时不断地让 CPU 在两个任务间的切换。

结合《Linux 内核完全注释》一书,得到了多任务切换的示例程序。

本节所要描述的内容,正是结合一个框架式的汇编程序(多任务切换程序, 书中提供的内容比较老,无法适应目前的各种工具、环境),在现有环境中加以处理并成功运行。

关于运行环境的说明,欢迎参考 理解 Linux Kernel (0)

阅读更多


理解 Linux Kernel (1) - BIOS

2018-08-19

前言

概述,我想我已经介绍过我开始这一些列博文的原因。 我不能担保我所进行的所有试验性操作都是对的,但是,至少这些在我所描述的环境下成功的运行了起来,并帮助我触及我始终敬畏而又敬而远之的硬件&OS

在《Linux内核完全注释》一书第三章——内核编程语言和环境,描述了用 as86 汇编语言构建 boot 引导程序,并最终通过 Bochs 仿真器在模拟开机通电后,BIOS Load boot 程序,通过显示器输出 Loading System...

这些,将是这里所要描述的主要内容。

阅读更多


理解 Linux Kernel (0) - 概述

2018-08-19

概述

之所以想要了解 Linux Kernel,与前一个月的 JVM ClassFile 的学习有这很大的关联。

说实话,刨除 JVM 的具体实现,Sun (或者现在该说是 Oracle) 确实将 Java 的底层逻辑设计得相当简单。

  1. 有限而统一的指令集(不超过 256 个,可以用 1 字节表示)
  2. 操作数栈+局部变量表共同实现的指令运算
  3. 高度封装的成员变量/方法的寻址方式
  4. ... (见识短浅,想不到了...以后再补充吧)

但是,与 JVM 模拟的虚拟机不同,实体机器有着更为复杂的结构。 最根本的,不同厂商的机器就带来了不同的 CPU 指令集,这就已经让人难以接受了。

其实最初,是想要继续去看看 Hotspot 虚拟机的。但是,混杂的代码(C++, Java, 平台相关各种实现) 带来了很大的阅读障碍。 最根本的,我甚至找不到一个学习的基本立足点,出发点(当然,也可能我根本就没仔细去看,哈哈)。

借着一次机会,我开始看《程序员的自我修养——链接、装载与库》一书。确实无论是 ELF 格式,静态链接与动态链接甚至 Linux 的内建函数 都给了我比较深刻的印象,向我展示了 C 更深入的一面。但是,macOS 给我带来了比较大的客观阻碍(即使用 Docker 容器得到了一个可用的 Linux 环境,但是否与直接建立在机器上的系统有所区别,此处还得打个问号)。 同时,书中的部分内容上下不统一,缺少前后文也是一个重大的问题。总之,这并不完全适合我这种初学者逐一进行书中所描述的全部实验。

最后,我决定展开对 Linux Kernel 的学习,试图通过对直接构架在硬件上的操作系统进行一番比较深入的学习。

期间,找过一些资料,也了解到 Linus Torvals 直接领导着的 Kernel 项目的官网;甚至,找到了各个版本的 kernel 源码(虽然确实地丢失了最早期 0.XX 的若干版本)。 不得不说,就目前来讲,我觉得《Linux内核完全注释》是最适合(打个问号,至少暂时是的)我学习的一书。

之后的若干博文,将都以《Linux内核完全注释》中的内容为基础,结合目前的实际需要,从而进行实操性的认知与学习。

阅读更多


Java Instrumentation

2018-08-15

Start

从现有的前置知识来说,我们能够认识到两个事实:

  1. Java Class 通过 ClassLoader 进行加载。 通过全限定名进行区分。当需要加载新的类时,ClassLoader 通过双亲委派机制判断是否已经加载过这个类。 换句话说: Class 一经加载,就不会尝试重复加载 (至少按绝大多数人的认知来说,确实是的)
  2. 有没有可能让被加载的 Class 与物理存储上的 .class 内容不同。 当然也是完全可以做到的。不管怎么说,CGlib 和 Java Proxy 也是一个耳熟能详的概念吧 (虽然可能不了解细节。在此,欢迎学习前置技能 CGlib Enhancer 主流程源码解析Java Proxy 源码解析。不过不影响本文后续内容)

另一个方面,也许绝大多数人都听说过所谓的热部署。但是究竟怎么才能做到 热部署(话题开得有点大哈。Y_Y 本文不讲这个)

操作字节码一定是一个逃不开的话题,毕竟 Class 就是所谓的被加载到内存的字节码嘛。

如何操作字节码? ASM, CGlib, Java Proxy, Javassist ? 不过这些都要等到需要被操作的类被加载了才行啊,似乎有点晚...

Java 提供了一个可行的机制,用来在 ClassLoader 加载字节码之前完成对操作字节码的目的

Instrumentation

java.lang.instrument.Instrumentation 类为提供直接操作 Java 字节码的又一个途径(虽然 Java Doc 的说明是用来检测 Java 代码的)

相信我这个说明是没有问题的。毕竟完成对代码检测的途径是直接修改字节码。

下列有两种方法可以达到目的

  1. 当 JVM 以指示一个代理类的方式启动时,将传递给代理类的 premain 方法一个 Instrumentation 实例。
  2. 当 JVM 提供某种机制在 JVM 启动之后某一时刻启动代理时,将传递给代理代码的 agentmain 方法一个 Instrumentation 实例。

话不多说,下面将全部以实例来展现对这种 JVM 检测机制(虽然例子已经脱离了检测的目的)的使用

阅读更多


JVM 指令简析

2018-07-24

在之前描述过包括 ASM, CGlib, Java Proxy 的基本内容之后,本文将就更为基础的 JVM 指令集进行简单而有效的介绍。

当然,在开始正文前,读者需要了解到,JVM 指令集这种类似于汇编的规范性内容,包含一百多个指令,若要求一一介绍。 那么,直接阅读 官方文档 绝对是比本文的内容更为详实且准确。

这篇文档的目的,只是为了使读者建立起关于 JVM 指令集基本的常识性观念。

阅读更多


Java Proxy 源码解析

2018-07-20

在 Java 整个生态里面, 通用的有两类动态代理的应用: Java Proxy 与 CGlib 代理。

从宽泛的区别来说,Java Proxy 只能对接口进行增强,而 CGlib 同时适用于类和接口的增强。 而且,业内普遍的认知是,CGlib 动态代理较之于 Java Proxy 在生成字节码的速度上也更为高效。

阅读更多


如何方便地获取 CGlib 生成类

2018-07-13

配置参数

命令行使用

在 java 启动命令中添加参数配置项 -Dcglib.debugLocation=<Custom Path>

编码实现

在执行 CGlib 获取新生成类之前,调用 System.setProperty("cglib.debugLocation", <Custom Path>)

阅读更多


CGlib Enhancer 主流程源码解析

2018-07-10

前言

此博文写作的目的:

  • (Core) 通过了解 CGlib Enhancer 的整个调用链,了解其对于唯一依赖的 ASM 库的调用方式。
  • 基于 Enhancer 对已有字节码进行增强的进一步理解与掌握。

阅读更多