-------------------------------------------
本文系作者原创, 欢迎大家转载!
转载请注明出处:netwalker.blog.chinaunix.net
-------------------------------------------

内核在某些应用中,为了实现某种机制,比如分页,或者提高访问效率需要保证数据或者指针地址对齐到某个特定的整数值,比如连接代码脚本。这个值必须是2N。数据对齐,可以看做向上圆整的一种运算。

  1. include/linux/kernel.h
  2. #define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1)
  3. #define __ALIGN_MASK(x, mask) (((x) + (mask))&~(mask))
  4. #define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a)))
  5. #define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0)

内核提供了两个用来对齐的宏ALIGN和PTR_ALIGN,一个实现数据对齐,而另一个实现指针的对齐。它们实现的核心都是__ALIGN_MASK,其中mask参数为低N位全为1,其余位全为0的掩码,它从圆整目标值2N - 1得到。__ALIGN_MASK得到对齐值,对于数据来说直接返回即可,而对于指针则需要进行强制转换。IS_ALIGNED宏用来判断当前值是否对齐与指定的值。内核中的分页对齐宏定义如下:

  1. arch/arm/include/asm/page.h
  2. /* PAGE_SHIFT determines the page size */
  3. #define PAGE_SHIFT 12
  4. #define PAGE_SIZE (1UL << PAGE_SHIFT)
  5. include/linux/mm.h
  6. /* to align the pointer to the (next) page boundary */
  7. #define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE)

PAGE_SIZE定义在体系架构相关的代码中,通常为4K。内核中提供的特性功能的对齐宏均是对ALIGN的扩展。下面提供一个代码示例,并给出结果:

  1. #include <stdio.h>
  2. ......
  3. int main()
  4. {
  5. int a = 0 ,i = 0;
  6. int *p = &a;
  7. for(; i < 6; i++)
  8. printf("ALIGN(%d, 4): %x\n", i, ALIGN(i, 4));
  9. printf("p:%p, PTR_ALIGN(p, 8): %p\n", p, PTR_ALIGN(p, 8));
  10. printf("IS_ALIGNED(7, 8): %d, IS_ALIGNED(16, 8): %d\n", IS_ALIGNED(7, 8), IS_ALIGNED(16, 8));
  11. return 0;
  12. }

对齐宏测试结果:

    1. ALIGN(0, 4): 0
    2. ALIGN(1, 4): 4
    3. ......
    4. ALIGN(4, 4): 4
    5. ALIGN(5, 4): 8
    6. p:0xbf96c01c, PTR_ALIGN(p, 8): 0xbf96c020
    7. IS_ALIGNED(7, 8): 0, IS_ALIGNED(16, 8): 1

1. 在linux内核中,经产会看到对齐ALIGN的调用,常见的如内存管理中page对齐,net_device中私有数据的获取等,本文是对ALIGN宏的一个简单分析。

1.1. 内核调用:在e100.c中,网卡irq处理函数 irqreturn_t e100_intr(int irq, void *dev_id) 调用netdev_priv(netdev)处理函数获取net_device的私有数据。

  

2105 static irqreturn_t e100_intr(int irq, void *dev_id)
2106 {
2107 struct net_device *netdev = dev_id;
2108 struct nic *nic = netdev_priv(netdev);

netdev_priv函数和ALIGN宏定义分别如下:

991 static inline void *netdev_priv(const struct net_device *dev)
992 {
993 return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
994 }

41 #define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
42 #define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))

1.2 用法解析:

    先说ALIGN的用法,ALIGN(x,a) 是为了使x以a为边界对齐,实现原理是给x加上一个最小的数,使x以a为边界对齐。举个例子,a = 8, x=0, ALIGN(x,a) 运算结果为0; a = 8, x = 3, 运算结果为8; a = 8, x = 11, 运算结果为16。

1.3原理分析:

    为了便于分析,假设所用到的数字都是16bit,typeof是类型定义分析的时候可以忽略,假设为了使x以8位界对齐。

a = 8, 则上面mask= 7,那么 __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) 用二进制表示为:

    X          xxxx xxxx

MASK                 + 0000 0111

    进一步,以上公式可以分为x低 三位全为0(加mask后无进位)和低三位不全为0(加mask后有进位)两种情况。

  1.3.1. x低三位全为0(加mask无进位)

     即 x = xxxx x000,这种情况下,__ALIGN_MASK(x,mask)运算结果仍为x,而x本身就为8的倍数,因此x以8为界对齐。

1.3.2 x低三位不全为0 (加mask有进位)

    x + mask 可理解为给x加7使得x向第四低位进位,同时低三位清零,运算后x = xxxx x000,同样为8的倍数,因此x以8为界对齐。

linux tricks 之 ALIGN解析.的更多相关文章

  1. linux device tree源代码解析--转

    //Based on Linux v3.14 source code Linux设备树机制(Device Tree) 一.描述 ARM Device Tree起源于OpenFirmware (OF), ...

  2. I.MX6 Linux U-boot 环境变量解析

    /********************************************************************************** * I.MX6 Linux U- ...

  3. linux网络配置完全解析

    概述:熟悉了windows下面的网络配置,对linux下的网络配置缺未必了解透彻.熟练掌握linux下的网络配置原理,能帮助我们更容易掌握网络传输原理:同时具备一些网络连接不通对应问题的排查能力.文本 ...

  4. linux ssh使用深度解析(key登录详解)

    linux ssh使用深度解析(key登录详解) SSH全称Secure SHell,顾名思义就是非常安全的shell的意思,SSH协议是IETF(Internet Engineering Task ...

  5. LINUX命令LS -AL 解析

    LINUX命令LS -AL 解析 linux命令ls -al 解析 ls是“list”的意思,与早期dos的命令dir功能类似.参数-al则表示列出所有的文件,包括隐藏文件,就是文件前面第一个字符为. ...

  6. Linux的DNS反向解析部署

    下面的部署是在Linux的DNS正向解析示例上进行修改的. 如果有什么问题或者错误,可以访问上篇帖子 下面开始有关DNS的服务部署.<DNS反向解析> 工具:虚拟机 centos7 配置: ...

  7. 【Linux开发】Linux V4L2驱动架构解析与开发导引

    Linux V4L2驱动架构解析与开发导引 Andrew按:众所周知,linux中可以采用灵活的多层次的驱动架构来对接口进行统一与抽象,最低层次的驱动总是直接面向硬件的,而最高层次的驱动在linux中 ...

  8. linux文件权限全面解析

    目录 linux文件权限全面解析 一:linux文件的权限有哪些? 1,权限分为3个部分 2,权限位 3,每一个权限拥有一个数字编号 4,在添加权限的时候,可以将权限加起来 5,linux添加权限命令 ...

  9. Arm Linux系统调用流程详细解析

    Linux系统通过向内核发出系统调用(system call)实现了用户态进程和硬件设备之间的大部分接口. 系统调用是操作系统提供的服务,用户程序通过各种系统调用,来引用内核提供的各种服务,系统调用的 ...

随机推荐

  1. Keil工程Lib库文件的制作和运用

    最近看了百度手环开源项目,发现所有的算法都被封装成了一个lib文件在keil中调用 也是第一次学习到. 问题引出:为什么要做成lib库? 1.有些方案公司为了将自己写的关键部分源代码不进行公开,但是同 ...

  2. C++入门经典-例3.14-使用while循环计算从1到10的累加

    1:代码如下: // 3.14.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> usin ...

  3. Java密码处理

  4. LeetCode124----二叉树中最大路径和

    给定一个非空二叉树,返回其最大路径和. 本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列.该路径至少包含一个节点,且不需要经过根节点. 示例 1: 输入: [1,2,3] 1 / \ 2 ...

  5. Python学习笔记:list的各种操作

    向一个列表中添加单个元素: my_list = []my_list.append('我爱你') 移除列表中的某个元素: my_list.pop(0) # 0是需要移除元素在列表中的index 或者是移 ...

  6. leetcode-easy-others-20 Valid Parentheses

    mycode   95.76% class Solution(object): def isValid(self, s): """ :type s: str :rtype ...

  7. Gson解析list类型的json串

    Gson gson = new Gson(); Type type = new TypeToken<List<Object>>() {}.getType(); List< ...

  8. 【转】c语言动态与静态分配

    https://blog.csdn.net/qq_43519310/article/details/85274836 https://blog.csdn.net/qq_38906523/article ...

  9. np.hstack和np.vstack

    np.vstack:按垂直方向(行顺序)堆叠数组构成一个新的数组 In[3]: import numpy as np In[4]: a = np.array([[1,2,3]]) a.shape Ou ...

  10. leetcode171 Excel列表序列号

    /** 可看做26进制到10进制转换问题:v=26*v+s[i]-'A'; **/ class Solution { public: int titleToNumber(string s) { ; f ...