- 博客(55)
- 资源 (3)
- 收藏
- 关注
原创 eBPF CO-RE 实现方式.md
本文分析了eBPF CO-RE(Compile Once - Run Everywhere)的实现机制。通过研究simple_bpf仓库代码和欧拉24.03环境下的.o文件,重点探讨了__builtin_preserve_access_index宏和BPF_CORE_READ宏的作用。这些宏在编译时会生成包含结构体/联合体偏移信息的记录,使得BPF程序能够通过CO-RE机制在不同内核版本上运行。文章还跟踪了bpf_object__relocate_core函数的执行过程,这是CO-RE实现的核心,负责处理.
2025-12-17 15:18:52
372
原创 ELF文件解析 elf.o 文件主要内容.md
本文分析了基于eBPF的ELF目标文件结构,重点研究了.o文件中kprobe/handle_mm_fault节的内容。通过readelf和llvm-objdump工具展示了该节的属性信息及反汇编结果,揭示了BPF指令的存储格式(8字节对齐)和SEC宏的实现机制。文章还探讨了libbpf对SHT_PROGBITS类型节的处理流程,包括符号表扫描规则和程序加载过程,为理解eBPF程序的ELF文件组织结构提供了实用参考。
2025-12-17 15:17:17
805
原创 网易云音乐前端一面算法题
本文探讨了跳跃游戏问题,给出两个解法判断是否能从数组起点跳到终点。第一种使用动态规划(空间复杂度O(n)),记录各位置可达性;第二种优化方案(空间复杂度O(1))实时跟踪最大可达位置。代码示例展示了两种解法在Go语言中的实现,分别测试了可达和不可达的输入案例,验证了算法的正确性。重点在于通过贪心策略优化空间使用,同时保持线性时间复杂度。
2025-11-10 13:18:53
114
原创 面试三面 手撕代码 手写sqrt 开平方
摘要:视频展示了两种实现平方根计算的方法。第一种使用递归二分查找,通过调整步长精度来处理小数位,支持指定小数位数。第二种方法分两步:先用整数二分查找确定整数部分,再逐位处理小数部分。两种方法都采用二分法原理,当mid的平方等于x时直接返回,否则根据比较结果调整查找范围。示例调用sqrt(2,4)返回1.4142,验证了算法的正确性。这些实现展示了面试中手写算法时对边界条件和精度控制的处理技巧。
2025-11-04 13:33:34
95
原创 glibc pthread_mutex_lock/unlock futex 互斥锁的实现
ys_futex (uaddr=0x4041a0, op=128, val=2, utime=0x0 <fixed_percpu_data>, uaddr2=0x0 <fixed_percpu_data>, val3=0) at kernel/futex/core.c:3806 #4 0xffffffff8119115a in do_syscall_x64 (nr=<optimized out>, regs=0xffff
2025-09-26 13:22:43
945
原创 ftrace function_graph 函数劫持实现方式
本文摘要: Linux内核ftrace机制实现分析,主要包含三个阶段: 准备阶段:通过gcc -pg编译选项在内核函数开头插入call _mcount指令,ftrace_init时将这些地址保存并替换为nop指令。 过滤设置:通过/sys/kernel/debug/tracing/set_ftrace_filter接口设置过滤条件,将过滤函数分别存入filter_hash和notrace_hash两个哈希表。 过滤执行:ftrace_startup时调用__ftrace_hash_rec_update,检查
2025-09-25 15:41:39
363
原创 linux内存管理-写时复制COW在内核代码实现
这篇文章通过代码跟踪分析了Linux写时复制(COW)的实现机制。作者首先设计了一个父子进程共享内存的测试程序,在内核缺页异常处设置断点进行调试追踪。通过分析调用栈发现,当子进程尝试修改共享页面时,内核会触发缺页异常,进入handle_pte_fault和do_wp_page函数处理写保护页。关键步骤是wp_page_copy函数会申请新页面、复制内容、更新页表项,并调整原页面的引用计数。文章还推测了clone时对页表和页面引用计数的操作。整个过程展现了Linux如何通过缺页异常处理机制实现高效的写时复制功
2025-09-23 17:10:06
582
原创 内存管理-伙伴系统合并块计算,__find_buddy_pfn,谁是我的伙伴???
本文分析了Linux伙伴系统中__find_buddy_pfn函数的实现原理。该函数通过位运算page_pfn ^ (1 << order)计算指定页框的伙伴位置,使得相邻块能按阶合并。文章详细解释了伙伴系统的初始化过程,通过__ffs()确定页框的初始阶数,并给出了1-13页的分配示例。还说明了不同阶数下伙伴页的合并规则,如0阶时4和5互为伙伴,1阶时4和6可合并为更高阶块。这些机制有效减少了内存碎片。
2025-09-19 11:18:14
151
原创 抓虫:unshared后执行命令dump
摘要:在执行unshare -m bash -c "mount --bind /opt/cmt/.venv/lib64 /lib64 && ls"命令时,bash进程出现段错误并产生核心转储。通过strace跟踪发现,进程在加载和卸载/lib64下的动态库(如libselinux.so.1)时,先通过mmap映射内存,随后执行munmap取消映射,最终因SIGSEGV信号(内存访问错误)崩溃。问题可能源于挂载新命名空间后动态链接库路径冲突,导致bash在准备执行ls时因内
2025-09-10 14:21:37
417
原创 通过重新构建依赖libtiff的软件包方式进行libtiff升级兼容性分析
文章摘要:本文通过对比动态库和测试程序的变化,分析了结构体新增成员、常量值修改和函数参数变更对程序的影响。检测结果显示,这些变化导致栈空间分配、变量偏移位置和全局变量值都发生了相应改变。此外,文章还探讨了libtiff依赖的ELF文件检测结果,指出29个无异常文件中存在4个汇编比对无差异但MD5不一致的情况。最后提出了构建环境一致性和调试包处理的相关建议。
2025-09-05 10:49:20
478
原创 抓虫:login进程的权能未获取
Linux权限能力调试分析 通过分析pam_cap.so模块发现: 该模块大部分符号未定义,仅实现少数与权限无关的函数 实际权限功能由libcap.so.2动态库提供 调试方法:替换系统login程序,将进程PID写入伪终端供调试 发现的异常:capsh --print命令输出的当前权限集不正确,存在格式错误问题 该案例展示了Linux权限管理模块的依赖关系和调试技巧,可用于排查权限设置异常问题。
2025-09-05 10:42:13
320
原创 抓虫:FD_SET访问非法栈地址溢出
Java调用so库时发生SIGSEGV错误,错误地址指向FD_SET操作。分析发现由于未对fd值进行<1024的校验,导致在计算__FD_ELT时发生栈溢出。通过objdump和寄存器回溯定位到问题代码位置,发现FD_SET宏定义中直接进行fd/64计算而未做边界检查,违反了POSIX规范要求fd必须为有效文件描述符的规定。建议使用gcc预编译检查宏展开情况,并注意fd_set的固定缓冲区特性,避免传入过大fd值导致未定义行为。
2025-09-05 10:37:32
161
原创 抓虫:loongarch64架构selinux强防开启程序执行报错execmod
摘要: 在loongarch64架构下开启强防后,发现strace、gdb等命令无法执行,审计日志显示缺少execmod权限。经分析,这是由于程序启用了TEXTREL(代码段重定位)特性,该特性在SELINUX下需要execmod权限保护。TEXTREL通常出现在位置无关代码(PIC)违反规范时,可能导致共享库加载问题或安全漏洞。通过readelf工具可查看程序的TEXTREL属性,验证其存在于二进制文件中。此情况在x86架构下运行正常,但在loongarch64架构下需额外处理。解决该问题需关注程序的PI
2025-09-05 10:33:19
1122
原创 抓虫:sw架构防火墙服务启动失败 Unable to initialize Netlink socket: 不支持的协议
Firewalld服务启动失败,调试发现是由于Netlink协议初始化失败导致。通过gdb追踪发现错误发生在nft_mnl_socket_open()函数中,该函数调用mnl_socket_open(NETLINK_NETFILTER)失败。分析依赖库发现该函数由libmnl.so.0提供,底层实际调用系统调用socket(AF_NETLINK,...)失败,可能是内核不支持NETLINK_NETFILTER协议或相关模块未加载。问题表现为"Unable to initialize Netlink
2025-09-05 10:24:53
860
原创 linux内存管理-四级页表映射计算
本文介绍了Linux内核地址映射机制,重点分析了从虚拟地址到物理地址的转换过程。通过0xffffea0000200000虚拟地址示例,详细说明了五级页表转换的步骤:PGD(39位偏移)、P4D(与PGD同级)、PUD(30位偏移)、PMD(21位偏移)和PTE(12位偏移)。每个页表项9位索引,通过位运算获取下一级页表地址,最终解析出物理地址。文中还展示了如何通过gdb调试工具查看各级页表内容,包括init_mm.pgd的初始位置和各级页表项的具体数值,帮助理解Linux内核地址映射的实现原理。
2025-08-28 17:58:27
440
原创 linux面试题:操作系统是怎么知道 IO 就绪的
这篇文章探讨了Linux系统中IO就绪后唤醒进程的机制。作者通过分析V站帖子中提到的面试问题,重点研究了ttwu(try to wake up)唤醒进程的过程。通过使用bpftrace工具追踪sched_wakeup事件,作者捕获到一个内核态调用栈,展示了从TTY终端写入到唤醒对端进程的完整路径。进一步通过gdb调试内核,作者详细分析了ttwu_do_activate函数调用栈,揭示了IO就绪后通过工作队列(worker_pool)唤醒阻塞进程的具体实现机制。文章最后指出,唤醒操作会从worker_pool
2025-08-15 10:15:18
1113
原创 从内核源码角度理解cgroup cpu中的cfs_period_us、cfs_quota_us配置
摘要:Linux内核5.10.202版本中,CFS调度器通过定时器机制实现带宽控制。当定时器周期到期时,会调用sched_cfs_period_timer回调函数,将任务的剩余可用时间(runtime)重置为预设的配额值(quota)。该机制通过__refill_cfs_bandwidth_runtime函数实现,确保任务在每个周期内获得固定的CPU时间配额。定时器初始化时配置了回调函数,并在到期时触发时间补充,从而维持公平调度。
2025-08-07 09:07:53
525
原创 抓虫:xfce桌面丢失权能
摘要:系统发现secadm用户登录后权能丢失问题。经排查,发现lightdm启动的xfce4-session进程未通过pam_cap.so模块继承权能。在/etc/pam.d/lightdm中添加auth required pam_cap.so keepcaps后,终端bash权能恢复。该问题一小时定位,但最终修复方案需仓库管理员根据lightdm三个PAM文件的具体作用进一步确认。
2025-08-06 10:18:02
209
原创 linux面试题:Ctrl+Alt+Fx 切换 tty 这个功能是在哪里实现的?
Linux终端切换功能实现分析 文章探讨了Linux系统中Ctrl+Alt+Fx切换tty功能的实现机制。通过分析发现: 终端切换功能主要由systemd-logind服务实现,通过ioctl(fd, VT_ACTIVATE)系统调用来完成 使用chvt命令可以直接切换终端,其核心逻辑是调用VT_ACTIVATE和VT_WAITACTIVE的ioctl操作 在SSH的pts终端中执行chvt可能无效,需要在真实tty终端中操作 通过strace跟踪发现,按键切换时会触发systemd-logind服务读取/
2025-07-31 15:13:52
925
原创 c++,lambda是匿名函数也可能不是函数,从汇编底层角度深入理解带捕获的lambda如何转化为std::function
摘要:本文通过分析C++中std::function的汇编实现,揭示了其内部工作机制。std::function是一个类而非单纯别名,其构造函数接收lambda捕获变量的地址而非函数指针。关键实现细节包括通过_Base_manager初始化函数对象,存储_M_invoker调用地址,以及利用完美转发传递参数。汇编代码显示function对象保存了lambda的调用器地址和管理器指针,验证了其作为通用函数包装器的类实现本质。(149字)
2025-07-22 16:07:34
818
原创 c++,从汇编角度看lambda
本文通过汇编分析揭示了C++ lambda表达式的工作机制。实验通过4个不同lambda示例,发现每个lambda都会生成对应的函数符号。不带捕获的lambda调用时传入无意义地址参数(类似this指针但大小为1);带捕获的lambda会将捕获变量按顺序排列形成内存块,调用时传入该内存块地址(类似结构体指针传参)。参数传递方式与常规函数一致,其中带默认参数的lambda会直接传入默认值。这些发现为后续研究lambda如何转换为std::function奠定了基础,展示了编译器对lambda的底层实现方式。
2025-07-22 14:39:09
303
原创 c++,stl库阅读之std::forword完美转发
摘要:完美转发通过std::forward解决模板函数中的引用丢失问题。它利用模板类型推导和引用折叠规则:当参数为通用引用(T&&)时,左值推导为T&,右值推导为T&&;通过remove_reference获取原始类型,再配合static_cast<_Tp&&>实现引用类型的完美转发。关键点包括:1)必须在模板函数中使用以自动推导类型;2)引用折叠规则确保引用类型正确传递;3)避免手动指定类型以保持自动化特性。示例代码演示了左值/右值的转发
2025-07-21 17:47:24
210
原创 c++,邪恶的花括号!列表初始化构造实现方式
文章摘要:讨论了C++中花括号初始化{}的使用场景,重点分析了std::vector的初始化列表构造实现。通过汇编代码解析,展示了initializer_list的内部工作机制:编译器会将{64,64}转换为数组指针和大小参数,并调用vector的初始化列表构造函数。文中还对比了四种初始化方式的适用场景,强调应根据代码意图选择最清晰可读的初始化方式,而非强制使用单一语法。最后指出initializer_list通过私有构造函数实现,编译器可直接调用。
2025-07-18 11:19:47
181
原创 C++无用的知识,inline不是宏,没有魔法!
摘要:《More Effective C++》指出,静态成员函数使用inline不会导致静态变量被复制,这与宏不同。示例代码显示,内联后的static_member()函数中静态变量i仍保持单一实例,输出结果为1和2,符合预期。相比之下,宏替换可能导致变量多次自增,产生意外结果(如4)。说明内联函数不会改变代码语义,而宏可能带来副作用。关键区别在于内联保持程序逻辑,而宏可能破坏设计意图。
2025-07-12 12:22:08
435
原创 c++,用 delete [] 释放 new 对象,会发生什么???
摘要:文章通过分析C++汇编代码,揭示了delete和delete[]的内存管理机制差异。delete[]通过访问数组对象前8字节获取元素个数(如new string[2]会在内存-8处存储2),而普通delete仅处理单个对象。在示例中:1) delete_normal(s)正确,2) delete_array(s)会越界访问;3) delete_normal(s2)会内存泄漏,4) delete_array(s2)正确。关键发现:new[]返回地址实际是"数组头-8",delete[
2025-07-11 14:21:48
371
原创 C++,从汇编角度看《虚拟继承的邪恶》
摘要:文章通过分析一个C++虚继承案例揭示了反直觉的输出结果(123和0)。代码中D(456)输出0的原因是虚继承初始化规则:1)虚基类A由最底层派生类D初始化;2)在D构造过程中,中间类C的构造函数未实际调用A(a),导致A被默认初始化为0。通过反汇编验证发现,编译器会生成两个版本的C构造函数,分别处理直接实例化和作为中间类的情况,解释了虚继承的底层实现机制。
2025-07-11 13:21:55
458
原创 c++的拷贝省略,返回局部类,如何实现?
本文探讨了C++中的拷贝省略(copy elision)优化机制。通过分析函数返回局部对象时的汇编代码,展示了编译器如何优化掉不必要的拷贝构造。在默认情况下,编译器会将返回对象的地址直接传递给调用方,避免临时对象的构造和拷贝。当使用-fno-elide-constructors选项时,编译器会生成完整的拷贝构造流程。文章通过对比两种编译方式的汇编代码,揭示了拷贝省略优化的实现机制,说明编译器如何通过参数传递优化来避免对象拷贝的开销。
2025-07-09 14:33:37
439
原创 c++的默认参数怎么回事?
摘要:通过分析C++程序的反汇编代码发现,带默认参数的函数(func_arg_with_default_val)和不带默认参数的函数(func_arg_without_default_val)在函数体部分完全相同。关键区别在于调用处:当调用带默认参数的函数时,若未显式传参,编译器会在调用时自动填充默认值(如main函数中默认传0)。这说明默认参数的处理是在调用阶段而非函数体内部实现的,与函数声明时的参数设置密切相关。该机制与C++的函数声明特性一致,验证了默认参数是在编译时根据函数声明信息处理的。
2025-07-02 11:30:52
152
原创 sysak中的iosdiag latency分析
总延迟 =block_getrq (类似于部分bcc工具中使用的blk_account_io_start hock位置)其余延迟为:block_getrq -> rq issue, rq issue -> rq done, rq done ->IO_ISSUE_DEVICE_POINT, // virtblk/scsi rq issue 驱动层这里 驱动代码位于 tracepoint/rq_issue 前后都有可能,位置随意。
2025-06-26 17:15:09
734
原创 iostat中的util原理
带上-x选项,最后一列是一个util列,这个值很重要,体现这个设备忙不忙。就像windows中的任务管理器看磁盘一样,如果磁盘导致性能非常卡,磁盘会使用率100%,延迟也很高。
2025-06-24 16:48:34
441
原创 摆脱跳板,使用bpftrace任意时刻暂停程序等待gdb附加
以前调试的时候,经常会用到一系列进程启动,需要附加到某一个进程,这个进程可能被其他程序唤起的,又很快就结束了,也不能直接执行这个程序复现情况,必须要在当时的现场中运行。上面的步骤中,/dev/pts/13是另一个终端,要把gdb的pid发送到另一个终端中,方便另一个终端中使用gdb附加到这个出错的gdb中。然后sleep(10)为了留出时间附加,在接下来execve将会将这个跳板替换为真正的gdb程序。
2025-04-03 10:23:23
357
原创 抓虫:捡个漏,loongarch架构gdb dump Assertion `supply_size == collect_size‘ failed.
loongarch架构的系统中,gcore命令用于转储进程,此时gcore会挂掉报错,一个断言错误。
2025-03-27 13:17:55
1136
原创 BCC-应用程序组件分析
追踪glibc中的函数用时以为例,域名的访问需要先解析域名为ip,再对ip进行访问。解析域名大多数应用层程序会通过调用glibc的相关函数解析。
2025-03-26 14:49:41
851
原创 BCC-CPU模块梳理
统计各类型硬中断消耗时间部分类型的中断处理分上半部和下半部,如网络,网络硬中断只负责唤醒软中断,硬中断只会耗时非常短。部分类型的中断处理和cpu数量成倍关系。
2025-03-25 15:37:09
684
原创 BCC-调度组件分析
第一个百分比 running/总,代表cpu的负载,类似于top命令看到的负载/cpu个数或windows任务管理器显示的cpu负载百分比。上面的示例就是8核cpu上8开启了8个任务但8个任务都设置了绑定到一个cpu上。用以计算cpu无人认领的几率,代表有任务都被挤在个别cpu了有的核心空闲,有的核心任务太多。统计任务加入调度队列或失去CPU时到获取CPU任务上线的时间间隔,以直方图呈现。统计任务加入调度队列或失去CPU时到获取CPU任务上线的时间间隔。统计进程从失去到重新获得CPU的次数,按栈计数。
2025-03-25 15:35:39
1185
原创 BCC-BIO组件分析
对于不同的硬盘物理形态该值的重要性可能不同,对于机械硬盘连续的IO请求对于磁头寻道可能更加友好,但对于SSD,IO是否连续影响可能较小。上方输出表示在一段间隔(默认3s)时,最长的(100%列)写耗时255us完成(on-device开始至结束),大部分写IO可在5us内完成。一次提交IO的长度对于硬盘的物理形态、总线协议也可能有不同的重要性,有些总线一次通信报文长度有限。该位置通常位于块设备驱动层,准备将队列中的扇区对设备操作,此。该位置通常位于块设备驱动层,准备将队列中的扇区对设备操作。
2025-03-25 15:34:13
910
原创 BCC-文件系统组件分析
对于和中的接口并不是会被vfs层直接调用,如果内核处理文件时已经获取到inode或其他表示文件的结构体信息可以直接调用文件系统层的接口操作文件。系统调用open时如果需要创建文件并不通过vfs_createvfs_create用于创建其他特殊类型文件,创建普通文件会在namei层直接调用文件系统的create接口。
2025-03-25 10:21:29
1010
原创 tracepoint真的比kprobe开销更小吗???
本文通过实践分析了eBPF程序在追踪点(tracepoint)和kprobe两种场景下的性能开销。作者选取了Linux内核中两个简单的函数blk_mq_sched_request_inserted和nonseekable_open作为测试对象,使用gdb调试内核,观察了eBPF附加前后指令的变化。研究发现,tracepoint会创建一份函数体副本,并修改跳转指令;当eBPF程序附加时,原有的调用路径会被替换为perf_trace调用。通过调试bpf_printk的执行路径,揭示了从tracepoint到eB
2025-03-13 12:29:11
908
原创 从操作系统新的视角看hello world
本篇紧跟上篇《栈-函数调用轨迹图》根据上一篇,知道栈的两个寄存器位置rbprsprip,在内存中便可以获取进程当前执行到了哪个位置,被哪个函数调用到的。虚拟内存:能运行主线linux的芯片都带有专门的设计支持虚拟内存。虚拟内存可以由内核分配给各个进程内存空间,这些分配的空间的内存地址对于各个进程而言不再是物理地址,而是虚拟的地址,每个进程的内存地址各自独立互不影响。每个进程申请到的内存就像是这个进程私有的内存一样使用,互相不影响。虚拟内存概念先了解即可,后面会用到。
2025-03-10 18:12:59
527
原创 栈-函数调用轨迹图
是一个和现在讲的栈有关的选项,以前的一些操作系统为了性能优化和常规程序栈的方式不太一样,以前的已经淘汰不再详述,现在较新的操作系统如。至于这两个寄存器函数跳转如何变化的,,每个函数的开头都是这样的两行,上一个函数的。指令的下一个指令位置(即跳转函数的返回位置)入栈,函数执行结束返回时就会跳转到到。代表新的栈的开始位置,由于栈是自顶向下的所以。区域就是函数内的一个栈帧,函数不发生跳转。函数的位置,这样就完成了一次栈的查找,在。的位置应该就是上一个函数的位置,也就是,指令的下一条位置,符合刚才提到的。
2025-03-09 22:01:53
393
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅