Ubuntu 18.04上的蓝牙连接问题

Ubuntu 18.04上的蓝牙连接问题

以前的博客当中有提到Ubuntu 16.04上用蓝牙耳机的事。现在系统升级到18.04后,发现每次计算机休眠再唤醒后,蓝牙耳机都无法连接。查看系统日志,发现有如下错误信息:

网上搜了一下,这个问题应该是一个蓝牙程序的bug,而且不限于Ubuntu 18,其他的发行版也有同样的问题。根据相关的bug报告,使用下面这个PPA更新bluez程序可以解决这个问题。希望Ubuntu及早将此问题修正。

Read More

[翻译] 简谈编译、汇编、链接和加载 – part VI

Tanslated from: http://www.tenouk.com/ModuleW.html W.10  运行时链接器和共享库的加载 使用共享库的程序启动时或这一个程序请求动态加载一个共享对象时会触发运行时链接器。因此符号的解析可以在下面两个过程中的任一个完成。 1. 加载时动态链接。程序被从磁盘上加载到内存中,其中未解析的引用被列出,加载器找到所有需要的外部符号,把所有对这些符号的引用更改为相对于程序基地址的内存地址。 2. 运行时动态链接。程序被从磁盘上加载到内存中,其中未解析的引用被原样保留。第一次对这些符号的访问是无效的,从而引发一个software trap。运行时动态链接器侦测到此次trap的原因并找到所需的外部符号。然后这个被访问的符号被加载到内存并被链接到程序中。 运行时链接器包含在C的运行时库中,它加载共享库(.so文件)时会完成几个任务。动态section提供信息给链接器,告诉它这个库文件链接的其它库文件。它同时提供需要哪些重定位(reloaction)操作以及需要解析的外部符号。运行时链接器会首先加载需要的其它库文件。然后为每个库文件执行重定位操作。有些重定位仅限于库文件本身,而有些则需要运行时链接器解析一个全局符号。对于后一种情况,运行时链接器会搜索一个库文件列表来寻找这个符号。在ELF文件中,会使用hash table来进行符号的查找,所以这个过程是很快的。一旦所有的重定位操作执行完毕,就开始调用在共享库文件的init部分中注册的初始化函数。一些C++的实现使用这个特性来调用全局contructor。   W.11  符号名称解析 当运行时链接器加载了共享库文件,还需要解析库文件中的符号。这里,符号解析的顺序和范围是很重要的。如果一个共享库调用的函数碰巧在几个库文件中都存在,那么搜索这个函数的顺序就至关重要了。这也是为什么操作系统为库文件加载定义了几个选项。所有具有全局范围的对象(可执行文件和库文件)会被保存到一个列表中(全局列表)。默认,任何全局对象的所有符号对加载进来的共享库都是可用的。全局列表开始时包含可执行文件以及程序启动时加载的库文件。   W.12 动态地址翻译 以内存管理的角度看,现代的具有多任务的操作系统通常会实现动态重定位,而非静态。所有程序在地址空间中的布局几乎是相同的。这个动态重定位(以处理器的角度,称为动态地址翻译)产生一下的假象: 1. 每个进程都可以使用以0开始的内存地址,即使其它进程已经在运行了,或者同一个程序被启动多次 2. 地址空间是受保护的 3. 甚至可以让进程认为它拥有比实际物理内存大得多的内存可用(虚拟内存) 动态重定位中,每次引用地址都会动态变化。虚拟内存地址(或者称为逻辑地址)由某个进程产生,而物理地址则是运行时在物理内存中的实际地址。地址的翻译通常由处理器内嵌的内存管理单元(MMU)完成。 虚拟地址是相对于进程而言的。每个进程都相信它的虚拟地址从0开始。进程完全不知道这个地址在物理内存中的实际地址。代码完全以虚拟地址的方式运行。 如果一个虚拟地址超出了进程的(实际)地址范围,MMU可以拒绝翻译此地址,如产生一个segmentation fault。这为所有进程提供了保护。 翻译过程中,我们还可以把进程地地址空间中的一部分在内存和磁盘间移动(称为swapping或paging),这就是为什么进程可以使用比实际物理内存还大的地址空间。 动态重定位可以以下图来表示:   More complete related information can be found at Tenouk’s buffer overflow Tutorial that include the stack construction and destruction for function call. You may also want to explore the Windows .NET Framework from the system perspective where the executable is called assembly…

Read More

[翻译] 简谈编译、汇编、链接和加载 – part V

W.8 运行时数据结构 一个进程就是一个运行着的程序。这意味着操作系统已经把程序的可执行文件加载到内存中,安排好了程序对它的参数和环境变量的访问权限,开始执行它的代码。通常一个进程有5个内存区域,如下表所示: Segment 描述 代码 – text segment 通常称为 text segment, 这里是程序的可执行代码指令区.  比如, 当一个程序同时运行多个实例时,Linux/Unix 会尽可能让他们共享text segment。 这个内存区的内容对应可执行文件的 text section. 初始化的数据 – data segment 非零值的静态分配的数据以及全局数据被加载到data segment.  一个程序有多个进程时,每个进程都有自己的data segment。这个内存区的内容对应可执行文件的 data section. 未初始化数据 – bss segment BSS 表示 ‘Block Started by Symbol’(符号开始的区域)。零值的静态分配的数据以及全局数据被加载到bss segment.  一个程序有多个进程时,每个进程都有自己的bss segment。运行时,bss里面的数据会被放入data segment。在可执行文件中,它们被保存在BSS section.  对Linux/Unix 的ELF格式,只有初始化为非零值的变量才会占用磁盘空间。 heap(堆) heap部分是动态内存(通过 malloc(), calloc(), realloc() 以及C++中的 new)的来源. Heap中的所有内容都是匿名的,因此你只能通过指针访问它的一部分。Heap中的内存被分配以后,进程的地址空间相应增长。虽然将(不再使用的)内存还给系统是可能的并会让进程的地址空间缩小,但是事实上几乎没有程序会这么做,因为它还会被分配给其它的进程。通过free()和delete释放的内存会回到heap中,并会在heap上形成洞。Heap通常向上增长,这意味着后续添加到heap中的内容其内存地址 要大于前面的内容。Heap通常开始于BSS后面  。Heap的结束以一个名为break的指针标志。你不能引用break后面的内容,但你可以通过brk()或sbrk()系统调用将break指向一个新地址来增加heap的地址空间。 Stack(栈) Stack是本地(自动)变量内存的来源。在C程序中,所有在函数体内定义的非静态变量都称为本地变量 。栈上数据的存储遵从后进先出(LIFO)原则。Stack保存了本地变量,临时信息,函数的参数,返回地址之类的信息。当一个函数被调用时,一个stack frame会被创建出来,并被PUSH到stack的顶端。这个stack frame包含的信息包括,调用此函数的地址,函数结束后应该返回的地址,函数的参数,本地变量以及其它函数需要的信息。信息的顺序每种系统和编译器不尽相同。当一个函数返回时,这个stack frame会被从stack上POP下去。stack的地址向下增长,意味着处于更深层的调用使用的内存地址更小。   当一个程序正在运行时,初始化的数据,BSS和heap区域通常被放在一个连续的内存区,称为data segment。 Stack segment和代码segment被data segment分隔开来。虽然理论上heap和stack可能会相遇,操作系统会阻止这种事件发生。不同的sections和segments的关系汇总成下表: 可执行文件section (磁盘文件) 地址空间 segment 程序内存 segment .text Text Code .data Data…

Read More

[翻译] 简谈编译、汇编、链接和加载 – part IV

W. 6: 共享对象的使用方式 要理解一个程序如何使用共享对象,让我们首先检查一下可执行文件的格式以及如何让程序开始运行。 w6.1一些ELF格式的细节 ELF(Executable and Linking Format, 可执行与链接格式)是一个二进制格式,用于SVR4 Unix和Linux系统。它是一种在磁盘上存储程序的格式。ELF不仅简化了创建共享文件的过程,也改进了运行时模块的动态加载。 W6.2 ELF块(sections) Linux及其它使用ELF格式的系统在可执行程序中定义了一些”块“。这些块用于为二进制文件提供指令,并且可被查看。重要的函数块包括GOT(Global Offset Table,全局偏移表),存储系统函数的地址,和PLT(Procedure Linking Table过程连接表),用于存储指向GOT的非直接链接;.init/.fini,用于内部初始化和关闭;.ctors/.dtors,用于constructors and destructors. 数据相关的块有.rodata,用于只读数据,.data用于已经初始化的数据,和.bss,用于未初始化的数据。 下面是一个ELF块的不完全列表(从低到高): .init – Startup .text – String .fini – Shutdown .rodata – Read Only .data – Initialized Data .tdata – Initialized Thread Data .tbss – Uninitialized Thread Data .ctors – Constructors .dtors – Destructors .got – Global Offset Table .bss – Uninitialized Data 你可以使用readelf或objdump程序来查看对象文件或可执行文件的块信息。 在下图中,展示了ELF文件的两种视图: 链接视图和执行视图 别忘了ELF的完整格式包含更多块。像前面解释过的,用于程序或库文件链接过程的链接视图处理对象文件内部的块。 对象文件的大部分信息都位于”块“中: 数据,指令,重定位信息,符号,debug信息等。执行视图用于程序执行时,处理对象是segment(也可以翻译为块)。segment是一种把相关的块组合起来的方式。比如,text segment包含了可执行代码,data segment包含了程序数据,dynamic segment包含了动态加载的相关信息。每个segment由一个或多个块组成。一个进程就是通过加载和分析segments来创建的。 操作系统根据程序的header table表里的信息把程序的各个segment复制到它的虚拟内存的segment。操作系统也可以利用segments来创建一个共享的内存资源。…

Read More

[翻译] 简谈编译、汇编、链接和加载 – part III

W.3 重定位记录(relocation records) 由于不同的对象文件会互相引用对方的代码和/或数据,所以不同的位置,这些不需要在链接时合并。比如,在下面的图中,包含main()的对象文件含有对funct()和printf()函数的调用。把所有对象文件链接在一起后,链接器使用重定位记录来定位那些需要填充的地址。 W.4 符号表 汇编成机器代码的过程会把代码中所有的标签移除,对象文件格式需要把这些信息存放在不同的地方。符号表就是做这个用的。符号表包含了一个名字及其在text和data块的偏移量的列表。反汇编程序可以把这个过程从对象文件或可执行文件翻译回来。   W.5  链接 链接让分开编译成为可能。如下图所示,一个可执行文件可以由多个可独立编译的源文件编译而来,而且每个文件都可以编译为自己的对象文件。 5.1 共享对象 在一个典型的系统上会有多个程序同时运行。每个程序都依赖于很多函数。而这些函数有很多是标准的C语言的库函数,比如printf(), malloc(), strcpy()等,有些则是非标准的或程序员自定义的函数。 如果每个程序都使用标准的C库(library),那就意味着每个程序都要在它的(地址空间)内部有一份C库。这样就会浪费很多资源,也影响效率和性能。 既然对C库文件的需求是共通的,那么如果每个程序都可以共享访问一份C库文件就是一个更好的选择,而不是每个程序都把标准C库文件加载一份到自己的内存地址中。 这个功能也是在链接过程中来实现的。有些对象是在链接的时候链接进来,而有些则是在程序运行时才链接进来(称为延迟链接或动态链接) 5.2 静态链接 静态链接表示一个程序和它需要的库文件在链接阶段就被链接器合并在一起了。这也意味着这个程序和库文件之间的绑定是固定的,且在程序开始运行之前就是已知的。同时也意味着我们无法改变这个结合状态,除非使用一个新版的库文件重新链接这个程序。 静态链接的程序所用的库(对象)一般是一个以.a为扩展名的文件。一个常见的例子就是标准的C库,libc.a。 如果不确定程序运行时能得到正确的库文件版本,或者想要测试一个新版的库文件,还不想把它作为共享库文件安装,这时可以使用静态链接。 对gcc来说,在编译/链接时使用-static选项会得到静态链接的程序 gcc –static filename.c –o filename 静态编译出的可执行文件会大很多,因为所有需要的信息和文件都要被放入可执行文件中。 5.3 动态链接 动态链接表示程序和它使用的特定库文件并非链接阶段就被链接在一起。相反,链接器在可执行文件中放入特定信息,告诉加载器(loader)代码在哪一个共享对象模块中以及应该使用哪一个运行时链接器来找到这个对象文件并将它与程序绑定。这意味着程序和共享对象之间的绑定是在运行时完成,且在程序开始执行之前。 这种类型的程序称为部分绑定可执行文件,因为它并非全部(符号或引用)可解析的。链接器在链接时间并不会将程序中引用的符号和库文件的特定代码结合起来。相反,链接器只是留一些类似这样的信息:这个程序调用的这个共享对象的这个函数,我只是记一下这个函数在哪个共享对象中。现在我要继续下面的工作。 共享对象中的符号会被验证以确认它们确实存在,但不会被合并到程序中。 链接器在可执行程序中存储了外部库文件的地址,用于找到哪些无法在程序中找到的符号。这造成的实际效果就是把(符号与代码之间的)绑定推迟到了程序运行时。 动态链接程序使用的共享对象通常使用.so的扩展名。一个最常见的例子就是标准C库libc.so。 动态链接的好处有: 1. 可执行文件的大小会比静态链接的文件小很多 2. 共享库文件可自行升级而不需要重新链接引用它的程序。 3. 软件商只需提供需要的库文件模块。 4. 结合虚拟内存技术,动态链接允许两个或更多进程共享一个只读的可执行模块,如标准C库。使用这个技术,任意时间只有一份库文件需要保留在内存中。节约了内存的使用。  

Read More

[翻译] 简谈编译、汇编、链接和加载 – part II

Tanslated from: http://www.tenouk.com/ModuleW.html W.2  对象文件与可执行文件 源文件经历汇编后会变成对象文件(文件名通常以.o为后缀),再经过链接后,就变成了可执行文件。 对象文件与可执行文件的格式有几种。如Linux上的ELF (Executable and Linking Format) 格式以及Windows上的 COFF (Common Object-File Format). 对象文件格式 描述 a.out Unix上最初的可执行文件格式.  它包含有三个块(sections):  text, data, and bss, 分别对应程序代码, 初始化过的数据以及未初始化的数据.  此格式无法包含排错信息。它能包括的唯一排错信息是被编码为一套带有不同属性的符号的、称为stabs的东西。 COFF COFF格式 (Common Object File Format) 由Unix SVR3引入 .可包含多个块, 每个块都有一个”块头(header)”. 块的数量是有限的.  COFF标准是包含排错信息的,但是也是有限的。此格式没有文件扩展名。 ECOFF COFF的一种变体.  ECOFF是一种扩展的COFF,最初为Mips 和 Alpha工作站设计. XCOFF 运行AIX的IBM RS/6000 使用了一种称为XCOFF (eXtended COFF)的格式. 这种格式中,COFF的块, 符号和行数信息被保留,但排错符号则变成了dbx风格的stabs,字符串被放进了.debug 块中 (而不是字符串表).  默认的对象文件名也是 a.out. PE Windows 9x 和 NT使用了PE (Portable Executable) 作为可执行文件的格式.  PE本质上是带有更多头部信息的COFF格式。文件名后缀是 .exe. ELF ELF (Executable and Linking Format) 出现在SVR4版本的 Unix.  ELF和COFF是相似的,都是把信息分成多个块来存放,但它解决了COFF的一些局限性.  现在的Unix类系统,包括GNU/Linux,…

Read More

[翻译] 简谈编译、汇编、链接和加载 – part I

Tanslated from: http://www.tenouk.com/ModuleW.html 本文详细介绍了一个C/C++程序从源文件到进程的过程。但它仍然只是我的一个缓冲溢出教程的节选。本文试图解释C/C++源码如何经历预处理(pre-processed)、编译(compiled)、链接(linked)以及最后被加载(loaded)为一个运行的进程(process)的过程。文章基于GCC。如果你使用了某个集成的IDE编程环境,那么这些过程就被这些IDE隐藏了。   W.1  编译器(compiler),汇编器(assembler)和链接器(linker) 不管使用何种操作系统或编程工具,C程序的编译过程一般有四步:预处理,编译,汇编和加载,直至最后变为一个单一的可执行文件。 预处理:处理包含文件,条件编译指令以及宏(Macros) 编译:将预处理过的源文件编译成汇编语言文件 汇编:将汇编语言文件转成带有偏移量的机器指令(assembly listing with offsets)。结果存储在一个对象文件中。 链接:将一个或多个对象文件以及库文件组合成一个(通常是可执行的)文件。在这个过程中,链接器需要解决外部对象的引用,为函数或过程调用和变量分配地址,更改代码块和数据以匹配新的地址(relocation). 下表列出了源文件的扩展名及其需要进行的处理: 文件扩展名 描述 file_name.c C源文件,需要进行预处理 file_name.i C源文件。不需要预处理。 file_name.ii C++ 源文件。不需要预处理。 file_name.h C 头文件 (不需要编译或链接。). file_name.cc file_name.cp file_name.cxx file_name.cpp file_name.c++ file_name.C C++源文件。需要进行预处理 。对于 file_name.cxx文件名, xx 必须就是两个小写的字母x 而 file_name.C, 最后的必须是大写字母C。 file_name.s 汇编代码. file_name.S 汇编代码. 需要进行预处理 file_name.o 默认的对象文件名。通常就是源文件加上 .o后缀。 下图则以图像的方式描述了从源文件到编译好的程序被加载为进程的过程:     — 待续

Read More

关于量化投资、IT及教育的一点随想

如果你在做股票, 你可能会意识到现在量化投资有越来越火的迹象。国内目前几个免费的量化投资平台,像米筐,优矿和聚宽等, 使用的编程语言都是Python。 我想要表达的意思是: 即使你无意从事IT行业, 你也应该学习一门编程语言, 熟练掌握一个操作系统的使用。而计算机或者是一个编程语言, 他们作为一个工具,对各行各业都有很大的影响。随着时间的推移, 这种影响会越来越大。 我也想就此再发挥一下, 聊一点青少年教育的科目问题。我对现在的学校教育最大的不满就是它们的目标。我觉得, 它们的目标是把学生, 我们的下一代, 培养称为一个合格的工人, 如果能让你毕业后找到一份工作, 他们就圆满完成了他的使命。而我理想中的教育, 是要把学生培养称为一个真正的人, 有能力, 有信仰,有追求,有同情心,有使命感。在现在的学校教育中, 我看不到这种迹象。 一个人要在社会上生存发展, 当然需要具备谋生的技能。所以教给学生们这些技能并没有错。错在学校把这个当成教育唯一的任务, 而且绝大部分的学校都在这样做。而且我并不认为国内的顶级院校就能免俗, 只是他们对“工作”的标准要求很高而已。 我觉得, 除了根据学生的特长和兴趣进行有针对行的技能培训以外,每个人从小到大都应该学习以下的内容: 如何了解自身, 了解“人”作为一种生物所具有的属性, 这涉及到生理学, 医疗保健或者说如何促进自身健康的基本知识。人类的心理特征, 性格的发展与形成, 人与他人或者说周围的环境如何互动,人类发展历史等。 了解我们生活的这个物理世界或者说自然环境。 这涉及到植物学,动物学, 天文地理, 数学、化学、物理学以及电子技术等等。 了解我们生存的这个社会。涉及的科目包括心理学(社会心理学, 犯罪心理学等等), 历史文化, 政治、经济以及宗教。 如何对个人以及真个社会的未来进行思考、探索。 涉及哲学, 更重要的是对以上所有东西的综合运用。 我个人认为心理学对每个人都是一个至关重要的一个科目。了解了相关的知识,你可以在学习时知道如何提高效率(认知心理学),  在取得成绩时如何避免被人嫉妒(社会心理学),  如何减少人身伤害发生的几率(犯罪心理学), 购物时如何抑制自己的冲动(消费心理学), 买股票时如何判断是否有泡沫(行为金融学, 我觉得还是心理学) …… 嗯, 我确实是认为对每门知识都应该有所了解。然后再根据自己的兴趣来确定深入学习的方向。 就扯到这吧!  

Read More
1 2 3 5