AI摘要 今日全球科技新闻涉及技术标准化、自动驾驶竞争、芯片股市场波动、AI产业碳排放、数字孪生技术、科技股下滑、中国厂商硬件成本优势、科技产业财富排名、科技行业增长潜力、科技公司吸引力等多个方面。这些新闻反映了技术发展、市场竞争、环境影响、投资趋势等关键议题，预示着科技行业未来的发展方向和潜在影响。 document.addEventListener('DOMContentLoaded', function() { const urlDisplay = document.getElementById('urlDisplay'); urlDisplay.textContent = "此内容根据文章生成，更内容请访问：" + window.location.href; }); 今日（2025-11-12）全球科技相关的重要新闻，按先后顺序整理。每条新闻我会从“背景＋公司/利益场景＋历史规律＋未来影响”四个维度分析。技术标准化的重要性上升概况：报道指出，随着边缘 AI 的扩展，业内越来越强调技术标准化以推动互操作性、安全性和可扩展性。(RCR Wireless News)背景／利益场景：大型芯片厂商和平台提供商（如 Qualcomm）通过制定标准（例如 5G 、边缘计算 AI 模块）有助于控制生态系统、锁定市场。标准化也能降低进入门槛、加速创新。历史规律：过去网络通信、USB 接口、蓝牙、WiFi 等标准化推动了规模化和成本下降。技术生态若无标准，容易形成碎片化、重复建设。未来影响：标准化趋势意味着中小厂商可能受益于通用平台，巨头则可能通过标准话语权获得更强控制。对国家／地区来说，制定或掌握标准可成为科技竞争力的新兵器。全球自动驾驶“机器人出租车”竞争加剧概况：报道指出，Waymo（美国）与中国的 Baidu Apollo Go 等公司正在全球范围内抢位自动驾驶出租车市场。(卫报)背景／利益场景：自动驾驶出租车代表未来出行模式转变，可减少人工成本、提高运营效率。公司通过抢占城市、城市群、国家牌照和运营规模建立壁垒。中国厂商硬件成本优势显著。历史规律：出行革命（如打车软件）通常先在高成本的发达市场展开，再在成本敏感或监管松的地区扩张。技术成熟→规模化→生态形成。未来影响：谁率先实现商业化大规模运营、谁能在数据、安全、法规方面建立优势，就可能在全球出行市场取得主导。对传统汽车、网约车行业是重大冲击。大型投资者抛售芯片巨头股份引发市场波动概况：日本 SoftBank Group 出售其在 Nvidia 的约 58 亿美元股份，引起半导体板块下挫。(巴伦周刊)背景／利益场景：Nvidia 是 AI 芯片龙头，其估值极高。SoftBank 此举被视为从“吉祥 AI 赌局”中抽身，转向更多布局如 OpenAI 等。历史规律：科技泡沫时期常见大资金在估值高峰时撤离。市场常警惕“估值超过实际应用能力”的风险。未来影响：此举可能成为 AI 行业估值警示标志。若多个大型投资者模仿，半导体与 AI 基础设施板块可能面临调整。对初创 AI 公司和芯片供应链也可能产生资金压力。 AI 产业导致的碳排放问题被定量化概况：一项研究称，美国 AI 应用预计每年新增约 90 万吨 CO₂ 排放，同时某些行业用电可增加至相当于 30 万 户家庭的级别。(科技探索)背景／利益场景：随着 AI 模型训练／推理规模激增，数据中心、电力消耗与环境影响成为企业／政府必须面对的新成本。历史规律：每一次技术革命（如互联网、云计算）最初忽视其能源成本，之后必然产生“环保反向监督”机制。未来影响：公司可能因为碳排放而被监管或需额外成本承担。绿色 AI 、高效模型将成为竞争优势。国家级监管和补贴策略也可能调整。数字孪生技术用于压缩空气储能系统效率提升概况：来自 University of Sharjah 的科学家开发了一种用于压缩空气能源储存（CAES）系统的“数字孪生（Digital Twin）”技术，可提前预测故障并提升效率。(Scimex)背景／利益场景：储能系统是可再生能源普及的关键瓶颈。数字孪生通过模拟与实时数据结合，有助于降低运维成本、延长设备寿命。企业可因此获得成本优势。历史规律：工业 4.0 时代强调“物理＋数字”融合，数字孪生正成为关键工具。从飞机、石油天然气，到现在储能系统，都是相似路径。未来影响：储能成本进一步降低将推动可再生能源规模化。一些技术提供商和系统集成商可能获得新增长。对传统化石能源系统构成中长期挑战。科技股普遍下滑、市场对 AI 热情或迎调整概况：因 SoftBank 售股及其他因素，全球科技股出现滑落，反映出市场对 AI 板块可能过热的担忧。(Investopedia)背景／利益场景：科技板块（尤其 AI、芯片、云基建）在近年获得大量溢价。大规模投资和预期可能先行于实际应用。资金流转方向若改变，将影响整个生态。历史规律：类似互联网泡沫时期，科技估值过高→资金撤出→板块调整。新的科技浪潮（如 AI）亦不可避免会经历“狂热→怀疑→重构”周期。未来影响：投资者与公司可能更关注“落地＋利润”而不是单纯“增长＋预期”。初创公司和资本市场可能更谨慎。技术集中度过高的公司短期内可能面临修正风险。全球自动驾驶竞争中的中国厂商硬件成本优势概况：文章指出，中国厂商在硬件成本上比美国同行显著有优势，这可能改变全球汽车智能化竞争格局。(彭博社)背景／利益场景：在自动驾驶汽车产业链中，硬件成本（传感器、计算单元、通讯模块）直接影响商业化可行性。中国厂商通过规模化、供应链本地化取得优势。历史规律：全球制造业竞争中，“在地化供应链＋低成本生产”长期是中国企业的优势。科技硬件若量产能够压价，则竞争力显著。未来影响：美国／欧洲厂商若无法削减成本，可能在中低端市场被中国厂商抢占。政策制定者可能更关注产业链安全与技术自主。科技产业中富豪榜中“科技大佬”主导财富排名概况：最新排行榜显示， Elon Musk 仍位居全球首富，其财富主要集中在电动汽车、太空、AI 等科技创新领域。(The Times of India)背景／利益场景：财富集中反映科技创新的高回报特性。但也意味着科技行业地位、政策与监管将更加引人关注。历史规律：从工业革命以来，经济发展最显著的财富累积往往出现在科技／创新阶段。如今亦如此。未来影响：科技大佬的社会影响力将提升，监管、税收、垄断审查、伦理问题均可能进一步强化。普通投资者与创业者也可能在“科技创新”中寻找机会。科技行业展望：2025 年仍有增长潜力概况：综合报告指出，尽管经济存在不确定性，科技行业在 2025 年依旧有望增长，尤其是在 IT 支出、AI 投资、创新应用上。(deloitte.com)背景／利益场景：企业数字化转型、云基础设施扩张、人工智能渗透等趋势仍在。厂商、服务商、硬件提供商都将从中受益。历史规律：科技投资常在经济回撤期先行，因为效率提升与成本节约成为企业重点。景气循环中，科技常为先行指标。未来影响：中小科技公司和创新型组织可能迎来机会，传统行业数字化转型也将加速。这可能带动就业结构、投资方向、供应链变化。科技公司员工排名、最佳雇主名单体现行业吸引力概况：根据 2025 年 Glassdoor 排名，科技公司（如 Apple Inc.、Microsoft、Meta Platforms）继续吸引人才。(BusinessBecause)背景／利益场景：人才竞争加剧，科技公司为争夺顶尖人才，会提供更优福利、更多创新项目，这反过来增强其创新能力和市场地位。历史规律：科技发展早期，吸引全球人才是形成创新集群的重要因素。如硅谷、深圳等。高质量人才与资本、技术互为支撑。未来影响：人才流向将影响哪些地区／公司能成为“科技中心”。对政府、教育体系、高校亦提出人才培养和吸引机制的新要求。好的，再补充 10 条全球科技新闻（共计 20 条），同样从“背景＋公司/利益场景＋历史规律＋未来影响”四维度分析如下：European Commission 拟放松 AI Act 监管概况：欧盟正在考虑对其于 2024 年生效的 AI 法规作出让步，包括延迟执行透明度罚款、给予企业一年的宽限期。 (金融时报)背景／利益场景：此法规原本定位为全球最严格的 AI 监管之一，但受大型科技公司及美国政府压力影响，欧盟出于竞争力与监管成本考虑而调整。历史规律：监管往往在技术爆发初期趋严，但随着行业成熟、企业适应、国际竞争加剧，监管框架可能被“优化”以兼顾创新与控制。未来影响：此举可能让欧洲在 AI 领域更具吸引力（减少合规负担），但也可能弱化其作为“安全 AI”监管先锋的定位。对跨大西洋／中欧科技竞争格局有长远意义。Microsoft Corporation 与 NVIDIA Corporation 在英国启动 “Agentic Launchpad”计划概况：微软联合英伟达以及英国／爱尔兰机构，启动专为“自主决策型 AI”（agentic AI）初创企业设计的项目，提供技术支持、云服务、市场渠道。 (Windows Central)背景／利益场景：微软与英伟达希望在英国打造人工智能创新枢纽，抢占未来 AI 基础设施与应用高地。初创企业可借助其生态加速商业化。历史规律：大型科技厂商常通过孵化／投资初创生态来锁定未来技术路径，如早期云平台、移动生态。如今 AI 也进入此加速期。未来影响：英国可能成为 AI 创业与应用的新聚集地；竞争加剧意味着全球 AI 生态将更分散。初创公司获益，但也面临巨头生态锁定与依赖风险。印度 Nasscom 等行业组织呼吁政府精化 AI 内容标签监管概况：印度技术行业团体呼吁 Ministry of Electronics and Information Technology (MeitY) 修订其 AI 生成内容标识规则，指出目前强制标识全部合成媒体或许会抑制创新。 (The Economic Times)背景／利益场景：对于印度大量 AI 平台、内容生成公司而言，严格的标识义务既是成本也是创新门槛。行业希望监管与国际接轨、灵活化。历史规律：许多国家在互联网内容、新媒体初期采用宽监管或鼓励发展，随后因问题累积才逐步收紧。印度或处于从鼓励到监管的过渡期。未来影响：印度若实现“有选择的合规＋支持创新”框架，可能成为 AI 内容生成与平台经济的新亮点。反之，如果标识规则过严，可能抑制本地创新。SK Keyfoundry 加速开发 SiC（碳化硅）功率半导体技术概况：SK Keyfoundry 推出碳化硅功率半导体技术。市场研究预测 SiC 市场将从 2025 起以年约 24% 速度增长至 2030 年。 (马尼拉时报)背景／利益场景：功率半导体是电动汽车、可再生能源、储能系统的重要组件。掌握 SiC 技术可获取下游大规模市场。歷史规律：制造新材料／新半导体往往伴随产业变革：如 GaN 、晶圆厂扩张等。企业抢先布局可获得技术壁垒。未来影响：如果 SiC 成本继续下降、性能提升，电动汽车与储能系统的效率将进一步优化。这对传统硅 Si 技术是挑战，也对整车厂与能源厂商形成新的议价格局。科技公司与英国儿童安全机构合作，测试 AI 工具生成滥用图像的能力概况：英国技术公司与儿童保护机构将有权根据新的法律，测试 AI 工具是否能生成儿童滥用图像。 (卫报)背景／利益场景：随着 AI 生成媒体（图片、视频）技术成熟，相关伦理与安全风险增大。厂商和监管机构都需加强防范机制。历史规律：技术往往先被用于创新和商业化，随后安全／伦理问题浮现，监管与严格测试才跟上。例如网络直播、无人机、深度伪造。未来影响：这种合作模式可能成为各国监管 AI 内容生成的新标准。厂商必须提升模型安全性、责任机制，这也可能增加成本、抑制某些功能。区块链技术在医疗支付与数据透明方面的新应用概况：在 Lisbon 的 Web Summit 期间，Health In Tech 与 AlphaTON Capital 将推出区块链在医疗行业的愿景：更快支付、透明数据、可信机制。 (PR Newswire)背景／利益场景：医疗行业长期存在数据孤岛、结算延迟、信任缺失。区块链可提供去中心化账本、不可篡改记录，降低成本、提高效率。历史规律：跨界技术（如 区块链）在初期多被金融领域采用，随后逐渐渗透至医疗、供应链、物流等；真正大规模落地需解决合规、隐私、可用性问题。未来影响：如果该模式成功复制，将推动医疗服务支付结构变革、推动数字健康经济进一步发展。风投可能更关注“区块链＋医疗”组合，而传统医疗系统需调整。全球 IT／企业技术整合：14 种方式帮助 IT 部门应对创新浪潮概况：一篇报告指出，企业 IT 部门需采取 14 种策略来跟上 AR/VR、AI PC、Arm 架构等新技术浪潮。 (computerworld.com)背景／利益场景：企业数字化转型不断深入，IT 架构、技术选型、人才配置都面临挑战。厂商提供工具、咨询与解决方案作为增长点。历史规律：每一次大型企业技术迭代（客户端／服务器 → 云 → 移动）都要求 IT 部门重新定位自身价值。此次 AI/AR/Arm 浪潮亦如此。未来影响：成功适应这些变化的企业将具备竞争优势，IT 服务商可能成为赢家。反之，难以适应的组织可能被淘汰或边缘化。消费电子旗舰机型 OnePlus 15 将于印度推出概况：OnePlus 15 将于 2025 年11 月13 日在印度发布，延续该品牌高性能与智能定制化路线。 (The Times of India)背景／利益场景：印度为智能手机全球增长最快市场之一。OnePlus 在该市场布局旗舰机，有助于品牌认知与高端份额提升。历史规律：手机厂商常通过旗舰新机在关键市场强化品牌、测试新技术，再向全球扩散。印度成为手机厂商必争之地。未来影响：如果机型受市场欢迎，可能刺激高端手机竞争加剧。也表明“性能＋智能化”已成为旗舰机标准。其他品牌或加快布局。企业联合在 COP30 展示“科技驱动的可持续发展”概况：数百家公司在 COP30 期间参与全球数字动员，展示科技应用于可持续发展、减碳、绿色创新。 (雅虎财经)背景／利益场景：环保和科技正在融合，公司不仅要创新也要“绿色”标签。科技能成为减碳、监测、能源管理的重要工具。历史规律：环保议题从边缘走入主流后，技术被纳入战略层面。以往云计算、数据中心曾被诟病，如今企业更强调“绿色 IT”。未来影响：绿色科技可能成为新的主流投资方向。公司如果不能体现“科技＋可持续”组合，可能被资本市场或监管边缘化。科技股市场震荡：投资者对 AI 板块谨慎情绪升温概况：有迹象显示，科技板块尤其 AI 相关的股市表现出现警惕迹象，因估值偏高、资金流向改变、监管不确定性增强。 (Reuters)背景／利益场景：科技公司长期享受高估值溢价，投资者希望从高速增长中获利。但增长要兑现、风险要可控。历史规律：科技泡沫时代总有“预期膨胀–兑现延迟–调整回落”三步。当前 AI 热潮亦可能遵循此路径。未来影响：投资策略将更倾向“落地＋现金流”，而非单纯增长预期。科技公司将被迫证明其商业模式与盈利能力。资金可能流向 “下一个可量化回报” 的领域。
成都市郫都区新冠肺炎疫情检测通知
AI摘要 成都市郫都区新增1例新冠肺炎确诊病例，患者为69岁女性。当地已启动应急预案，追踪密切接触者并进行核酸检测，同时对相关地区实施封控管理。郫都区发布疫情检测通知，要求特定时间段内前往过郫都区人民医院和太平村11组的人员于12月8日24时前进行核酸检测。 document.addEventListener('DOMContentLoaded', function() { const urlDisplay = document.getElementById('urlDisplay'); urlDisplay.textContent = "此内容根据文章生成，更内容请访问：" + window.location.href; }); 12月7日，四川成都郫都区新增1例新冠肺炎确诊病例。患者卢某某，女，69岁，无业，居住于郫筒街道太平村11组。12月6日，因咳嗽、咳痰等症状，前往郫都区人民医院就诊。入院体温36.2℃，肺部CT显示双肺散在分布磨玻璃影。12月7日，经市疾控中心复核新冠病毒核酸检测阳性。经省、市、区专家会诊，综合临床、影像学表现和实验室核酸检查结果，诊断为确诊病例（普通型），已转运至成都市公共卫生临床医疗中心医院隔离治疗。省、市、区立即启动应急预案，组织21支流调、检测和消杀专业队伍，全面开展流行病学调查，核酸检测、环境消杀和现场管控等措施。目前，已追踪到的密切接触者及密接的密接均已落实集中隔离观察和核酸检测。已对区人民医院、患者居住地等地区实施封控管理及人员和环境核酸检测。下一步，将继续做好相关人员流行病学调查溯源和核酸检测工作，严格落实属地防控责任，做好闭环管理和各项防疫工作。同时，请广大市民做好个人防护，配合做好新冠肺炎疫情防控工作。成都郫都区发布新型冠状病毒肺炎疫情检测通知12月7日13时25分，成都市郫都区官方微博发布新型冠状病毒肺炎疫情检测通知。广大市民朋友：因疫情防控需要，为切实保障广大群众健康安全，严防疫情扩散，请下列人员于2020年12月7日内参加核酸检测。一、检测对象2020年12月6日8时至2020年12月7日8时期间前往过郫都区人民医院的所有患者、陪同人员、医护人员、工作人员。2020年11月23日至12月7日到过郫筒街道太平村11组的人员。二、检测时间2020年12月8日24时前三、检测地点地点一：郫都区郫筒街道蜀都新邨党群服务中心（郫筒街道蜀信路二段290号）地点二：西汇·西都会（郫筒街道鹃兴路63号）四、注意事项请参加核酸检测的人员，服从现场工作人员的统一安排，有序排队参加检测，做好个人防护。如有不适，及时前往医疗机构就诊。成都市郫都区新型冠状病毒肺炎疫情防控指挥部2020年12月7日来源：郫都发布
AI摘要 本文是一篇关于Golang汇编入门的知识总结，作者分享了自己在学习Golang底层实现机制时对Golang汇编的理解。文章首先解释了为什么需要汇编语言，然后介绍了程序与进程的概念，接着深入讲解了Go汇编的相关知识，包括核心寄存器、常用操作指令等。文章还提供了如何输出Go汇编的方法，并通过对一个简单Go函数的汇编代码进行分析，帮助读者理解Go汇编的实现过程。最后，文章还介绍了一些Go调试工具，如gdb和delve，并总结了学习Go汇编需要熟悉的几个方面。 document.addEventListener('DOMContentLoaded', function() { const urlDisplay = document.getElementById('urlDisplay'); urlDisplay.textContent = "此内容根据文章生成，更内容请访问：" + window.location.href; }); 作者：ivansli，腾讯 IEG 运营开发工程师在深入学习 Golang 的 runtime 和标准库实现的时候发现，如果对 Golang 汇编没有一定了解的话，很难深入了解其底层实现机制。在这里整理总结了一份基础的 Golang 汇编入门知识，通过学习之后能够对其底层实现有一定的认识。0. 为什么写本文平时业务中一直使用 PHP 编写代码，但是一直对 Golang 比较感兴趣，闲暇、周末之余会看一些 Go 底层源码。近日在分析 go 的某些特性底层功能实现时发现：有些又跟 runtime 运行时有关，而要掌握这一部分的话，有一道坎是绕不过去的，那就是 Go 汇编。索性就查阅了很多大佬们写的资料，在阅读之余整理总结了一下，并在这里分享给大家。本文使用 Go 版本为 go1.14.11. 为什么需要汇编众所周知，在计算机的世界里，只有 2 种类型。那就是：0 和 1。计算机工作是由一系列的机器指令进行驱动的，这些指令又是一组二进制数字，其对应计算机的高低电平。而这些机器指令的集合就是机器语言，这些机器语言在最底层是与硬件一一对应的。显而易见，这样的机器指令有一个致命的缺点：可阅读性太差（恐怕也只有天才和疯子才有能力把控得了）。为了解决可读性的问题以及代码编辑的需求，于是就诞生了最接近机器的语言：汇编语言（在我看来，汇编语言更像一种助记符，这些人们容易记住的每一条助记符都映射着一条不容易记住的由 0、1 组成的机器指令。你觉得像不像域名与 IP 地址的关系呢？）。1.1 程序的编译过程以 C 语言为例来说，从 hello.c 的源码文件到 hello 可执行文件，经过编译器处理，大致分为几个阶段：编译器在不同的阶段会做不同的事情，但是有一步是可以确定的，那就是：源码会被编译成汇编，最后才是二进制。2. 程序与进程源码经过编译之后，得到一个二进制的可执行 文件。文件这两个字也就表明，目前得到的这个文件跟其他文件对比，除了是具有一定的格式（Linux 中是 ELF 格式，即：可运行可链接。executable linkable formate）的二进制组成，并没什么区别。在 Linux 中文件类型大致分为 7 种：b: 块设备文件c：字符设备文件d：目录-：普通文件l：链接s：socketp：管道通过上面可以看到，可执行文件 main 与源码文件 main.go，都是同一种类型，属于普通文件。（当然了，在 Unix 中有一句很经典的话：一切皆文件）。那么，问题来了：什么是程序？什么是进程？2.1 程序维基百科告诉我们：程序是指一组指示计算机或其他具有消息处理能力设备每一步动作的指令，通常用某种程序设计语言编写，运行于某种目标体系结构上。从某个层面来看，可以把程序分为静态程序、动态程序：静态程序：单纯的指具有一定格式的可执行二进制文件。动态程序：则是静态可执行程序文件被加载到内存之后的一种运行时模型（又称为进程）。2.2 进程首先，要知道的是，进程是分配系统资源的最小单位，线程(带有时间片的函数)是系统调度的最小单位。进程包含线程，线程所属于进程。创建进程一般使用 fork 方法(通常会有个拉起程序，先 fork 自身生成一个子进程。然后，在该子进程中通过 exec 函数把对应程序加载进来，进而启动目标进程。当然，实际上要复杂得多)，而创建线程则是使用 pthread 线程库。以 32 位 Linux 操作系统为例，进程经典的虚拟内存结构模型如下图所示：其中，有两处结构是静态程序所不具有的，那就是 运行时堆(heap)与 运行时栈(stack)。运行时堆从低地址向高地址增长，申请的内存空间需要程序员自己或者由 GC 释放。运行时栈从高地址向低地址增长，内存空间在当前栈桢调用结束之后自动释放(并不是清除其所占用内存中数据，而是通过栈顶指针 SP 的移动，来标识哪些内存是正在使用的)。3. Go 汇编对于 Go 编译器而言，其输出的结果是一种抽象可移植的汇编代码，这种汇编（Go 的汇编是基于 Plan9 的汇编）并不对应某种真实的硬件架构。Go 的汇编器会使用这种伪汇编，再为目标硬件生成具体的机器指令。伪汇编这一个额外层可以带来很多好处，最主要的一点是方便将 Go 移植到新的架构上。相关的信息可以参考 Rob Pike 的 The Design of the Go Assembler。要了解 Go 的汇编器最重要的是要知道 Go 的汇编器不是对底层机器的直接表示，即 Go 的汇编器没有直接使用目标机器的汇编指令。Go 汇编器所用的指令，一部分与目标机器的指令一一对应，而另外一部分则不是。这是因为编译器套件不需要汇编器直接参与常规的编译过程。相反，编译器使用了一种半抽象的指令集，并且部分指令是在代码生成后才被选择的。汇编器基于这种半抽象的形式工作，所以虽然你看到的是一条 MOV 指令，但是工具链针对对这条指令实际生成可能完全不是一个移动指令，也许会是清除或者加载。也有可能精确的对应目标平台上同名的指令。概括来说，特定于机器的指令会以他们的本尊出现， 然而对于一些通用的操作，如内存的移动以及子程序的调用以及返回通常都做了抽象。细节因架构不同而不一样，我们对这样的不精确性表示歉意，情况并不明确。汇编器程序的工作是对这样半抽象指令集进行解析并将其转变为可以输入到链接器的指令。The most important thing to know about Go’s assembler is that it is not a direct representation of the underlying machine. Some of the details map precisely to the machine, but some do not. This is because the compiler suite needs no assembler pass in the usual pipeline. Instead, the compiler operates on a kind of semi-abstract instruction set, and instruction selection occurs partly after code generation. The assembler works on the semi-abstract form, so when you see an instruction like MOV what the toolchain actually generates for that operation might not be a move instruction at all, perhaps a clear or load.Or it might correspond exactly to the machine instruction with that name. In general, machine-specific operations tend to appear as themselves, while more general concepts like memory move and subroutine call and return are more abstract. The details vary with architecture, and we apologize for the imprecision; the situation is not well-defined.The assembler program is a way to parse a description of that semi-abstract instruction set and turn it into instructions to be input to the linker.Go 汇编使用的是 caller-save模式，被调用函数的入参参数、返回值都由调用者维护、准备。因此，当需要调用一个函数时，需要先将这些工作准备好，才调用下一个函数，另外这些都需要进行内存对齐，对齐的大小是 sizeof(uintptr)。3.1 几个概念在深入了解 Go 汇编之前，需要知道的几个概念：栈：进程、线程、goroutine 都有自己的调用栈，先进后出（FILO）栈帧：可以理解是函数调用时，在栈上为函数所分配的内存区域调用者：caller，比如：A 函数调用了 B 函数，那么 A 就是调用者被调者：callee，比如：A 函数调用了 B 函数，那么 B 就是被调者3.2 Go 的核心寄存器go 汇编中有 4 个核心的伪寄存器，这 4 个寄存器是编译器用来维护上下文、特殊标识等作用的：寄存器说明SB(Static base pointer)global symbolsFP(Frame pointer)arguments and localsPC(Program counter)jumps and branchesSP(Stack pointer)top of stackFP: 使用如symbol+offset(FP)的方式，引用 callee 函数的入参参数。例如arg0+0(FP)，arg1+8(FP)，使用 FP 必须加 symbol ，否则无法通过编译(从汇编层面来看，symbol 没有什么用，加 symbol 主要是为了提升代码可读性)。另外，需要注意的是：往往在编写 go 汇编代码时，要站在 callee 的角度来看(FP)，在 callee 看来，(FP)指向的是 caller 调用 callee 时传递的第一个参数的位置。假如当前的 callee 函数是 add，在 add 的代码中引用 FP，该 FP 指向的位置不在 callee 的 stack frame 之内。而是在 caller 的 stack frame 上，指向调用 add 函数时传递的第一个参数的位置，经常在 callee 中用symbol+offset(FP)来获取入参的参数值。SB: 全局静态基指针，一般用在声明函数、全局变量中。SP: 该寄存器也是最具有迷惑性的寄存器，因为会有伪 SP 寄存器和硬件 SP 寄存器之分。plan9 的这个伪 SP 寄存器指向当前栈帧第一个局部变量的结束位置(为什么说是结束位置，可以看下面寄存器内存布局图)，使用形如 symbol+offset(SP) 的方式，引用函数的局部变量。offset 的合法取值是 [-framesize, 0)，注意是个左闭右开的区间。假如局部变量都是 8 字节，那么第一个局部变量就可以用 localvar0-8(SP) 来表示。与硬件寄存器 SP 是两个不同的东西，在栈帧 size 为 0 的情况下，伪寄存器 SP 和硬件寄存器 SP 指向同一位置。手写汇编代码时，如果是 symbol+offset(SP)形式，则表示伪寄存器 SP。如果是 offset(SP)则表示硬件寄存器 SP。务必注意：对于编译输出(go tool compile -S / go tool objdump)的代码来讲，所有的 SP 都是硬件 SP 寄存器，无论是否带 symbol（这一点非常具有迷惑性，需要慢慢理解。往往在分析编译输出的汇编时，看到的就是硬件 SP 寄存器）。PC: 实际上就是在体系结构的知识中常见的 pc 寄存器，在 x86 平台下对应 ip 寄存器，amd64 上则是 rip。除了个别跳转之外，手写 plan9 汇编代码时，很少用到 PC 寄存器。通过上面的讲解，想必已经对 4 个核心寄存器的区别有了一定的认识（或者是更加的迷惑、一头雾水）。那么，需要留意的是：如果是在分析编译输出的汇编代码时，要重点看 SP、SB 寄存器（FP 寄存器在这里是看不到的）。如果是，在手写汇编代码，那么要重点看 FP、SP 寄存器。3.2.1 伪寄存器的内存模型下图描述了栈桢与各个寄存器的内存关系模型，值得注意的是要站在 callee 的角度来看。有一点需要注意的是，return addr 也是在 caller 的栈上的，不过往栈上插 return addr 的过程是由 CALL 指令完成的（在分析汇编时，是看不到关于 addr 相关空间信息的。在分配栈空间时，addr 所占用空间大小不包含在栈帧大小内）。在 AMD64 环境，伪 PC 寄存器其实是 IP 指令计数器寄存器的别名。伪 FP 寄存器对应的是 caller 函数的帧指针，一般用来访问 callee 函数的入参参数和返回值。伪 SP 栈指针对应的是当前 callee 函数栈帧的底部（不包括参数和返回值部分），一般用于定位局部变量。伪 SP 是一个比较特殊的寄存器，因为还存在一个同名的 SP 真寄存器，真 SP 寄存器对应的是栈的顶部。在编写 Go 汇编时，当需要区分伪寄存器和真寄存器的时候只需要记住一点：伪寄存器一般需要一个标识符和偏移量为前缀，如果没有标识符前缀则是真寄存器。比如(SP)、+8(SP)没有标识符前缀为真 SP 寄存器，而 a(SP)、b+8(SP)有标识符为前缀表示伪寄存器。3.2.2 几点说明我们这里对容易混淆的几点简单进行说明：伪 SP 和硬件 SP 不是一回事，在手写汇编代码时，伪 SP 和硬件 SP 的区分方法是看该 SP 前是否有 symbol。如果有 symbol，那么即为伪寄存器，如果没有，那么说明是硬件 SP 寄存器。伪 SP 和 FP 的相对位置是会变的，所以不应该尝试用伪 SP 寄存器去找那些用 FP+offset 来引用的值，例如函数的入参和返回值。官方文档中说的伪 SP 指向 stack 的 top，可能是有问题的。其指向的局部变量位置实际上是整个栈的栈底（除 caller BP 之外），所以说 bottom 更合适一些。在 go tool objdump/go tool compile -S 输出的代码中，是没有伪 SP 和 FP 寄存器的，我们上面说的区分伪 SP 和硬件 SP 寄存器的方法，对于上述两个命令的输出结果是没法使用的。在编译和反汇编的结果中，只有真实的 SP 寄存器。3.2.3 IA64 和 plan9 的对应关系在 plan9 汇编里还可以直接使用的 amd64 的通用寄存器，应用代码层面会用到的通用寄存器主要是: rax, rbx, rcx, rdx, rdi, rsi, r8~r15 这些寄存器，虽然 rbp 和 rsp 也可以用，不过 bp 和 sp 会被用来管理栈顶和栈底，最好不要拿来进行运算。plan9 中使用寄存器不需要带 r 或 e 的前缀，例如 rax，只要写 AX 即可: MOVQ $101, AX = mov rax, 101下面是通用通用寄存器的名字在 IA64 和 plan9 中的对应关系:3.3 常用操作指令下面列出了常用的几个汇编指令（指令后缀 Q 说明是 64 位上的汇编指令）助记符指令种类用途示例MOVQ传送数据传送MOVQ 48, AX // 把 48 传送到 AXLEAQ传送地址传送LEAQ AX, BX // 把 AX 有效地址传送到 BXPUSHQ传送栈压入PUSHQ AX // 将 AX 内容送入栈顶位置POPQ传送栈弹出POPQ AX // 弹出栈顶数据后修改栈顶指针ADDQ运算相加并赋值ADDQ BX, AX // 等价于 AX+=BXSUBQ运算相减并赋值SUBQ BX, AX // 等价于 AX-=BXCMPQ运算比较大小CMPQ SI CX // 比较 SI 和 CX 的大小CALL转移调用函数CALL runtime.printnl(SB) // 发起调用JMP转移无条件转移指令JMP 0x0185 //无条件转至 0x0185 地址处JLS转移条件转移指令JLS 0x0185 //左边小于右边，则跳到 0x01854. 汇编分析说了那么多，it is code show time。4.1 如何输出 Go 汇编对于写好的 go 源码，生成对应的 Go 汇编，大概有下面几种方法 1 先使用go build -gcflags "-N -l" main.go 生成对应的可执行二进制文件 再使用go tool objdump -s "main\." main 反编译获取对应的汇编反编译时 "main\." 表示只输出 main 包中相关的汇编 "main\.main" 则表示只输出 main 包中 main 方法相关的汇编方法 2 使用go tool compile -S -N -l main.go 这种方式直接输出汇编方法 3 使用go build -gcflags="-N -l -S" main.go 直接输出汇编注意：在使用这些命令时，加上对应的 flag，否则某些逻辑会被编译器优化掉，而看不到对应完整的汇编代码-l 禁止内联 -N 编译时，禁止优化 -S 输出汇编代码4.2 Go 汇编示例go 示例代码package main func add(a, b int) int{ sum := 0 // 不设置该局部变量sum，add栈空间大小会是0 sum = a+b return sum} func main(){ println(add(1,2))}编译 go 源代码，输出汇编go tool compile -N -l -S main.go截取主要汇编如下："".add STEXT nosplit size=60 args=0x18 locals=0x10 0x0000 00000 (main.go:3) TEXT "".add(SB), NOSPLIT, $16-24 0x0000 00000 (main.go:3) SUBQ $16, SP ;;生成add栈空间 0x0004 00004 (main.go:3) MOVQ BP, 8(SP) 0x0009 00009 (main.go:3) LEAQ 8(SP), BP ;; ...omitted FUNCDATA stuff... 0x000e 00014 (main.go:3) MOVQ $0, "".~r2+40(SP) ;;初始化返回值 0x0017 00023 (main.go:4) MOVQ $0, "".sum(SP) ;;局部变量sum赋为0 0x001f 00031 (main.go:5) MOVQ "".a+24(SP), AX ;;取参数a 0x0024 00036 (main.go:5) ADDQ "".b+32(SP), AX ;;等价于AX=a+b 0x0029 00041 (main.go:5) MOVQ AX, "".sum(SP) ;;赋值局部变量sum 0x002d 00045 (main.go:6) MOVQ AX, "".~r2+40(SP) ;;设置返回值 0x0032 00050 (main.go:6) MOVQ 8(SP), BP 0x0037 00055 (main.go:6) ADDQ $16, SP ;;清除add栈空间 0x003b 00059 (main.go:6) RET ...... "".main STEXT size=107 args=0x0 locals=0x28 0x0000 00000 (main.go:9) TEXT "".main(SB), $40-0 ...... 0x000f 00015 (main.go:9) SUBQ $40, SP ;; 生成main栈空间 0x0013 00019 (main.go:9) MOVQ BP, 32(SP) 0x0018 00024 (main.go:9) LEAQ 32(SP), BP ;; ...omitted FUNCDATA stuff... 0x001d 00029 (main.go:10) MOVQ $1, (SP) ;;add入参：1 0x0025 00037 (main.go:10) MOVQ $2, 8(SP) ;;add入参：2 0x002e 00046 (main.go:10) CALL "".add(SB) ;;调用add函数 0x0033 00051 (main.go:10) MOVQ 16(SP), AX 0x0038 00056 (main.go:10) MOVQ AX, ""..autotmp_0+24(SP) 0x003d 00061 (main.go:10) CALL runtime.printlock(SB) 0x0042 00066 (main.go:10) MOVQ ""..autotmp_0+24(SP), AX 0x0047 00071 (main.go:10) MOVQ AX, (SP) 0x004b 00075 (main.go:10) CALL runtime.printint(SB) 0x0050 00080 (main.go:10) CALL runtime.printnl(SB) 0x0055 00085 (main.go:10) CALL runtime.printunlock(SB) 0x005a 00090 (main.go:11) MOVQ 32(SP), BP 0x005f 00095 (main.go:11) ADDQ $40, SP ;;清除main栈空间 0x0063 00099 (main.go:11) RET ......这里列举了一个简单的 int 类型 加法示例，实际开发中会遇到各种参数类型，要复杂的多，这里只是抛砖引玉 :)4.3 Go 汇编解析针对 4.2 输出汇编，对重要核心代码进行分析。4.3.1 add 函数汇编解析TEXT "".add(SB), NOSPLIT|ABIInternal, $16-24TEXT "".add TEXT 指令声明了 "".add 是 .text 代码段的一部分，并表明跟在这个声明后的是函数的函数体。在链接期，""这个空字符会被替换为当前的包名: 也就是说，"".add 在链接到二进制文件后会变成 main.add(SB) SB 是一个虚拟的伪寄存器，保存静态基地址(static-base) 指针，即我们程序地址空间的开始地址。"".add(SB) 表明我们的符号位于某个固定的相对地址空间起始处的偏移位置 (最终是由链接器计算得到的)。换句话来讲，它有一个直接的绝对地址: 是一个全局的函数符号。NOSPLIT: 向编译器表明不应该插入 stack-split 的用来检查栈需要扩张的前导指令。在我们 add 函数的这种情况下，编译器自己帮我们插入了这个标记: 它足够聪明地意识到，由于 add 没有任何局部变量且没有它自己的栈帧，所以一定不会超出当前的栈。不然，每次调用函数时，在这里执行栈检查就是完全浪费 CPU 时间了。$0-1624 指定了调用方传入的参数+返回值大小（24 字节=入参 a、b 大小 8字节*2+ 返回值8字节）> 通常来讲，帧大小后一般都跟随着一个参数大小，用减号分隔。(这不是一个减法操作，只是一种特殊的语法) 帧大小 $24-8 意味着这个函数有 24 个字节的帧以及 8 个字节的参数，位于调用者的帧上。如果 NOSPLIT 没有在 TEXT 中指定，则必须提供参数大小。对于 Go 原型的汇编函数，go vet 会检查参数大小是否正确。In the general case, the frame size is followed by an argument size, separated by a minus sign. (It’s not a subtraction, just idiosyncratic syntax.) The frame size $24-8 states that the function has a 24-byte frame and is called with 8 bytes of argument, which live on the caller’s frame. If NOSPLIT is not specified for the TEXT, the argument size must be provided. For assembly functions with Go prototypes, go vet will check that the argument size is correct.SUBQ $16, SPSP 为栈顶指针，该语句等价于 SP-=16（由于栈空间是向下增长的，所以开辟栈空间时为减操作），表示生成 16 字节大小的栈空间。MOVQ $0, "".~r2+40(SP)此时的 SP 为 add 函数栈的栈顶指针，40(SP)的位置则是 add 返回值的位置，该位置位于 main 函数栈空间内。该语句设置返回值类型的 0 值，即初始化返回值，防止得到脏数据（返回值类型为 int，int 的 0 值为 0）。MOVQ "".a+24(SP), AX从 main 函数栈空间获取入参 a 的值，存到寄存器 AXADDQ "".b+32(SP), AX从 main 函数栈空间获取入参 b 的值，与寄存器 AX 中存储的 a 值相加，结果存到 AX。相当于 AX=a+bMOVQ AX, "".~r2+40(SP)把 a+b 的结果放到 main 函数栈中, add(a+b)返回值所在的位置ADDQ $16, SP归还 add 函数占用的栈空间4.3.2 函数栈桢结构模型根据 4.2 对应汇编绘制的函数栈桢结构模型还记得前面提到的，Go 汇编使用的是 caller-save模式，被调用函数的参数、返回值、栈位置都需要由调用者维护、准备吗？在函数栈桢结构中可以看到，add()函数的入参以及返回值都由调用者 main()函数维护。也正是因为如此，GO 有了其他语言不具有的，支持多个返回值的特性。4.4 Go 汇编语法这里重点讲一下函数声明、变量声明。4.4.1 函数声明来看一个典型的 Go 汇编函数定义// func add(a, b int) int// 该add函数声明定义在同一个 package name 下的任意 .go文件中// 只有函数头，没有实现 // add函数的Go汇编实现// pkgname 默认是 ""TEXT pkgname·add(SB), NOSPLIT, $16-24 MOVQ a+0(FP), AX ADDQ b+8(FP), AX MOVQ AX, ret+16(FP) RETGo 汇编实现为什么是 TEXT 开头？仔细观察上面的进程内存布局图就会发现，我们的代码在是存储在.text 段中的，这里也就是一种约定俗成的起名方式。实际上在 plan9 中 TEXT 是一个指令，用来定义一个函数。定义中的 pkgname 是可以省略的，(非想写也可以写上，不过写上 pkgname 的话，在重命名 package 之后还需要改代码，默认为 "") 编译器会在链接期自动加上所属的包名称。中点 · 比较特殊，是一个 unicode 的中点，该点在 mac 下的输入方法是 option+shift+9。在程序被链接之后，所有的中点 ·都会被替换为句号 .，比如你的方法是 runtime·main，在编译之后的程序里的符号则是 runtime.main。简单总结一下, Go 汇编实现函数声明，格式为: 静态基地址(static-base) 指针 | | add函数入参+返回值总大小 | |TEXT pkgname·add(SB),NOSPLIT,$16-24 | | |函数所属包名 函数名 add函数栈帧大小函数栈帧大小：局部变量+可能需要的额外调用函数的参数空间的总大小，不包括调用其它函数时的 ret address 的大小。(SB): SB 是一个虚拟寄存器，保存了静态基地址(static-base) 指针，即我们程序地址空间的开始地址。"".add(SB) 表明我们的符号位于某个固定的相对地址空间起始处的偏移位置 (最终是由链接器计算得到的)。换句话来讲，它有一个直接的绝对地址: 是一个全局的函数符号。NOSPLIT: 向编译器表明，不应该插入 stack-split 的用来检查栈需要扩张的前导指令。在我们 add 函数的这种情况下，编译器自己帮我们插入了这个标记: 它足够聪明地意识到，add 不会超出当前的栈，因此没必要调用函数时在这里执行栈检查。4.4.2 变量声明汇编里的全局变量，一般是存储在 .rodata或者 .data段中。对应到 Go 代码，就是已初始化过的全局的 const、var 变量/常量。使用 DATA 结合 GLOBL 来定义一个变量。DATA 的用法为:DATA symbol+offset(SB)/width, value大多数参数都是字面意思，不过这个 offset 需要注意：其含义是该值相对于符号 symbol 的偏移，而不是相对于全局某个地址的偏移。GLOBL 汇编指令用于定义名为 symbol 的全局变量，变量对应的内存宽度为 width，内存宽度部分必须用常量初始化。GLOBL ·symbol(SB), width下面是定义了多个变量的例子:DATA ·age+0(SB)/4, $8 ;; 数值8为 4字节GLOBL ·age(SB), RODATA, $4 DATA ·pi+0(SB)/8, $3.1415926 ;; 数值3.1415926为float64, 8字节GLOBL ·pi(SB), RODATA, $8 DATA ·year+0(SB)/4, $2020 ;; 数值2020为 4字节GLOBL ·year(SB), RODATA, $4 ;; 变量hello 使用2个DATA来定义DATA ·hello+0(SB)/8, $"hello my" ;; `hello my` 共8个字节DATA ·hello+8(SB)/8, $" world" ;; ` world` 共8个字节(3个空格)GLOBL ·hello(SB), RODATA, $16 ;; `hello my world` 共16个字节 DATA ·hello<>+0(SB)/8, $"hello my" ;; `hello my` 共8个字节DATA ·hello<>+8(SB)/8, $" world" ;; ` world` 共8个字节(3个空格)GLOBL ·hello<>(SB), RODATA, $16 ;; `hello my world` 共16个字节大部分都比较好理解，不过这里引入了新的标记 <>，这个跟在符号名之后，表示该全局变量只在当前文件中生效，类似于 C 语言中的 static。如果在另外文件中引用该变量的话，会报 relocation target not found 的错误。5. 手写汇编实现功能在 Go 源码中会看到一些汇编写的代码，这些代码跟其他 go 代码一起组成了整个 go 的底层功能实现。下面，我们通过一个简单的 Go 汇编代码示例来实现两数相加功能。5.1 使用 Go 汇编实现 add 函数Go 代码package main func add(a, b int64) int64 func main(){ println(add(2,3))}Go 源码中 add()函数只有函数签名，没有具体的实现（使用 GO 汇编实现）使用 Go 汇编实现的 add()函数TEXT ·add(SB), $0-24 ;; add栈空间为0，入参+返回值大小=24字节 MOVQ x+0(FP), AX ;; 从main中取参数：2 ADDQ y+8(FP), AX ;; 从main中取参数：3 MOVQ AX, ret+16(FP) ;; 保存结果到返回值 RET把 Go 源码与 Go 汇编编译到一起(我这里，这两个文件在同一个目录)go build -gcflags "-N -l" .我这里目录为 demo1，所以得到可执行程序 demo1，运行得到结果：55.2 反编译可执行程序对 5.1 中得到的可执行程序 demo1 使用 objdump 进行反编译，获取汇编代码go tool objdump -s "main\." demo1得到汇编......TEXT main.main(SB) /root/go/src/demo1/main.go main.go:5 0x4581d0 64488b0c25f8ffffff MOVQ FS:0xfffffff8, CX main.go:5 0x4581d9 483b6110 CMPQ 0x10(CX), SP main.go:5 0x4581dd 7655 JBE 0x458234 main.go:5 0x4581df 4883ec28 SUBQ $0x28, SP ;;生成main栈桢 main.go:5 0x4581e3 48896c2420 MOVQ BP, 0x20(SP) main.go:5 0x4581e8 488d6c2420 LEAQ 0x20(SP), BP main.go:6 0x4581ed 48c7042402000000 MOVQ $0x2, 0(SP) ;;参数值 2 main.go:6 0x4581f5 48c744240803000000 MOVQ $0x3, 0x8(SP) ;;参数值 3 main.go:6 0x4581fe e83d000000 CALL main.add(SB);;call add main.go:6 0x458203 488b442410 MOVQ 0x10(SP), AX main.go:6 0x458208 4889442418 MOVQ AX, 0x18(SP) main.go:6 0x45820d e8fe2dfdff CALL runtime.printlock(SB) main.go:6 0x458212 488b442418 MOVQ 0x18(SP), AX main.go:6 0x458217 48890424 MOVQ AX, 0(SP) main.go:6 0x45821b e87035fdff CALL runtime.printint(SB) main.go:6 0x458220 e87b30fdff CALL runtime.printnl(SB) main.go:6 0x458225 e8662efdff CALL runtime.printunlock(SB) main.go:7 0x45822a 488b6c2420 MOVQ 0x20(SP), BP main.go:7 0x45822f 4883c428 ADDQ $0x28, SP main.go:7 0x458233 c3 RET main.go:5 0x458234 e89797ffff CALL runtime.morestack_noctxt(SB) main.go:5 0x458239 eb95 JMP main.main(SB) ;; 反编译得到的汇编与add_amd64.s文件中的汇编大致操作一致TEXT main.add(SB) /root/go/src/demo1/add_amd64.s add_amd64.s:2 0x458240 488b442408 MOVQ 0x8(SP), AX ;; 获取第一个参数 add_amd64.s:3 0x458245 4803442410 ADDQ 0x10(SP), AX ;;参数a+参数b add_amd64.s:5 0x45824a 4889442418 MOVQ AX, 0x18(SP) ;;保存计算结果 add_amd64.s:7 0x45824f c3 RET通过上面操作，可知：(FP)伪寄存器，只有在编写 Go 汇编代码时使用。FP 伪寄存器指向 caller 传递给 callee 的第一个参数使用 go tool compile / go tool objdump 得到的汇编中看不到(FP)寄存器的踪影6. Go 调试工具这里推荐 2 个 Go 代码调试工具。6.1 gdb 调试 Go 代码测试代码package main type Ier interface{ add(a, b int) int sub(a, b int) int} type data struct{ a, b int} func (*data) add(a, b int) int{ return a+b} func (*data) sub(a, b int) int{ return a-b} func main(){ var t Ier = &data{3,4} println(t.add(1,2)) println(t.sub(3,2))}编译 go build -gcflags "-N -l" -o main使用 GDB 调试> gdb main GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-80.el7Copyright (C) 2013 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.htmlThis is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-redhat-linux-gnu".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from /root/go/src/interface/main...done.Loading Go Runtime support.(gdb) list // 显示源码14 func (*data) add(a, b int) int{15 return a+b16 }1718 func (*data) sub(a, b int) int{19 return a-b20 }212223 func main(){(gdb) list24 var t Ier = &data{3,4}2526 println(t.add(1,2))27 println(t.sub(3,2))28 }29(gdb) b 26 // 在源码26行处设置断点Breakpoint 1 at 0x45827c: file /root/go/src/interface/main.go, line 26.(gdb) rStarting program: /root/go/src/interface/main Breakpoint 1, main.main () at /root/go/src/interface/main.go:2626 println(t.add(1,2))(gdb) info locals // 显示变量t = {tab = 0x487020 <data,main.Ier>, data = 0xc000096000}(gdb) ptype t // 打印t的结构type = struct runtime.iface { runtime.itab *tab; void *data;}(gdb) p *t.tab.inter // 打印t.tab.inter指针指向的数据$2 = {typ = {size = 16, ptrdata = 16, hash = 2491815843, tflag = 7 '\a', align = 8 '\b', fieldAlign = 8 '\b', kind = 20 '\024', equal = {void (void *, void *, bool *)} 0x466ec0, gcdata = 0x484351 "\002\003\004\005\006\a\b\t\n\f\r\016\017\020\022\025\026\030\033\034\036\037\"&(,-5<BUXx\216\231\330\335\377", str = 6568, ptrToThis = 23808}, pkgpath = {bytes = 0x4592b4 ""}, mhdr = []runtime.imethod = {{name = 277, ityp = 48608}, {name = 649, ityp = 48608}}}(gdb) disass // 显示汇编Dump of assembler code for function main.main: 0x0000000000458210 <+0>: mov %fs:0xfffffffffffffff8,%rcx 0x0000000000458219 <+9>: cmp 0x10(%rcx),%rsp 0x000000000045821d <+13>: jbe 0x458324 <main.main+276> 0x0000000000458223 <+19>: sub $0x50,%rsp 0x0000000000458227 <+23>: mov %rbp,0x48(%rsp) 0x000000000045822c <+28>: lea 0x48(%rsp),%rbp 0x0000000000458231 <+33>: lea 0x10dc8(%rip),%rax # 0x469000 0x0000000000458238 <+40>: mov %rax,(%rsp) 0x000000000045823c <+44>: callq 0x40a5c0 <runtime.newobject>常用的 gdb 调试命令runcontinuebreakbacktrace 与 frameinfo break、localslist 命令print 和 ptype 命令disass除了 gdb，另外推荐一款 gdb 的增强版调试工具 cgdbhttps://cgdb.github.io/效果如下图所示，分两个窗口：上面显示源代码，下面是具体的命令行调试界面(跟 gdb 一样)：#### 6.2 delve 调试代码delve 项目地址https://github.com/go-delve/delve带图形化界面的 dlv 项目地址https://github.com/aarzilli/gdlvdlv 的安装使用，这里不再做过多讲解，感兴趣的可以尝试一下。gdb 作为调试工具自是不用多说，比较老牌、强大，可以支持多种语言。delve 则是使用 go 语言开发的，用来调试 go 的工具，功能也是十分强大，打印结果可以显示 gdb 支持不了的东西，这里不再做过多讲解，有兴趣的可以查阅相关资料。7. 总结对于 Go 汇编基础大致需要熟悉下面几个方面：通过上面的例子相信已经让你对 Go 的汇编有了一定的理解。当然，对于大部分业务开发人员来说，只要看的懂即可。如果想进一步的了解，可以阅读相关的资料或者书籍。最后想说的是：鉴于个人能力有限，在阅读过程中你可能会发现存在的一些问题或者缺陷，欢迎各位大佬指正。如果感兴趣的话，也可以一起私下交流。8. 参考资料在整理的过程中，部分参考、引用下面链接地址内容。有一些写的还是不错的，感兴趣的同学可以阅读。[1] https://github.com/cch123/golang-notes/blob/master/assembly.md plan9 assembly[2] https://segmentfault.com/a/1190000019753885 汇编入门[3] https://www.davidwong.fr/goasm/ Go Assembly by Example[4] https://juejin.im/post/6844904005630443533#heading-3[5] https://github.com/go-internals-cn/go-internals/blob/master/chapter1_assembly_primer/README.md[6] https://lrita.github.io/2017/12/12/golang-asm/[7] https://chai2010.cn/advanced-go-programming-book/ch3-asm/ch3-01-basic.html
AI摘要 本文探讨了学习新编程语言的方法和常见问题。作者指出，仅阅读官方文档和查看开源项目代码对初学者来说并不足够，因为这些资料可能过于复杂或不全面。作者建议初学者从官方提供的Step-By-Step代码开始学习，这些代码由浅入深、有质量保证且更新及时。同时，作者强调了实践的重要性，建议初学者通过小项目逐步提高。最后，作者呼吁开发者社区中的老手和新手之间需要更多的耐心和理解，以减少信息不对称带来的矛盾。 document.addEventListener('DOMContentLoaded', function() { const urlDisplay = document.getElementById('urlDisplay'); urlDisplay.textContent = "此内容根据文章生成，更内容请访问：" + window.location.href; }); 首先要说，这并不是一篇教你如何学习的文章，因为到今天为止我也没有找到一种通用的方法来解决如何学习的问题。但是在探索的道路上，我确实产生过一些思路，我想把这些思考的过程分享出来让大家探讨。如果这对你有帮助的话，那我会非常高兴。我最近在学习 Rust ，这是一门很酷但是相对冷门的语言（学习冷门语言可能是我的一大爱好，比如我就非常喜欢 CoffeeScript ，这是 JavaScript 的一门方言）。自从在某些语言的舒适区待久之后，经常会产生自己无所不能的错觉，这也是我不断想学习新语言的一大动力。而我的学习过程跟大多数人类似，就是先在网上找文档然后自学。而在看文档的过程中，我就发现了一些问题。手册的作用“去看文档喽。”这是老鸟在面对新手时最喜欢扔的一句话，我通常也是这么扔给自己的。但当你打开一门语言的手册，你会发现它除了教你语法外，几乎没有教你什么其它东西。于是你会陷入这样一个境地：“背下来了么？”“背不下来，太难懂了。”“再看一遍，给我背下来。”。。。“背下来了么？”“大部分背下来了。”“给我写个程序，实现个XX功能。”“不会。。。”“。。。”在一个高级开发者眼里，你会了语法理所当然就应该会写程序了，但实际情况并非如此。这让我想起前段时间跟一个朋友关于目前编程教育市场的一个讨论。我出于自己的经验提出一个想法：让大牛开发者来教新手入门。在我的设想中，大牛开发者拥有强大的实战经验，以及丰富的专业知识，更是自带光环，这不比现在市场上那些半吊子的讲师好多了。在我为自己“伟大”的想法得意的时候，朋友给我浇了一盆冷水。他告诉我这样根本行不通，大牛根本不知道菜鸟需要什么知识，你可能以为基础语法讲清楚就好了，人家却连编辑器是什么都不清楚。设想一下，让一个大学教授去教一群小学生，这对两者来说都是一种灾难吧。这些语言的创造者，或者文档的作者，无疑都是一些大神。它们在撰写一个语言手册的过程中，只能尽量负责地把这个语言的全貌准确地有组织地展现给你。然而这种全面的展现，对于一个没有任何引导的初学者来说并不完全是一件好事。简单来说就是，你会在一些次要的事情上浪费太多时间，而一些主要的概念又没有理解透彻。关于看真实代码当觉得文档满足不了你的时候，老鸟们往往会扔给你第二招：看代码。看什么代码呢？那还用说，当然是被业界奉为经典的，在 GitHub 上至少有一万颗星的知名开源项目代码啦。当你怀着崇敬的心情，打开扔给你的网址，看着满屏幕的代码时，你会对自己问出那三个经典的哲学问题。这是什么东西？它是怎么做到的？为什么要这么写？搞不好某些人还会因为惊吓过度，从而失去了学习下去的信心。那么让我们一起来看看这些代码里有什么鬼东西，会吓得新手信心不足。大段的注释说一件事你们不要笑，在我还是个萌新的时候，我曾经对这些穿插在代码中的神秘文字产生了深深的困惑，我还以为它们对代码有某种加成作用，以至于我还试验过把注释去掉会对代码执行产生什么影响。而现实中好的代码会让后面的维护者方便很多，但不好的甚至错误的注释会让人迷惑不已。语法糖语法糖是个好东西，它大大简化了我们的编程过程，高手用起语法糖写起代码来简直不要太爽，所以越强大的项目这玩意儿越多。但是对于初学者来说，语法糖隐藏了一些细节，而且让语法看起来很怪异。有些代码如果你用标准语法来写是很好懂的，但如果用语法糖来写的话很难让人一下子明白。初学者为了弄懂这些语法往往要花大量时间，但其实这些时间在这个阶段是没必要的浪费。你看不懂它觉得它是一个很重要的东西，其实它只是一个做工精巧的小玩意儿，离开了它这些代码照样能工作。而随着你的经验丰富，也可以随时随地用起来，用的方法可能也不尽相同。代码里的重点对于一个开源项目来说，往往 50% 的代码可能都是在适配各种不同的运行环境，将系统的 API 抽象成项目里通用的接口，这部分代码除非你自己要做类似的项目，要不然的话对初学者来说参考意义不大。更何况，为了适配某些系统奇葩的运行环境，开发者往往会大开脑洞，创造出一些非常奇怪的代码。这些旁门左道充满了玄学和不确定性，初学者看多了可能会发生如武侠小说里练功出差错的结果：走火入魔。剩下的代码里 20% 是项目内部的接口抽象和定义，最后 30% 才是真正值得看的东西，它们往往散落在各个地方，但又为了一个设计核心服务。让初学者识别出这些代码来，未免太强人所难。野文档这是我自己的一个定义，我把一切非官方的开发文档都称为野文档。初学者会在搜索引擎里得到大量的相关文档，他们很多是学习心得，很多人在写这篇文章时水平可能比你也高不了多少。这就造成了这些文档的水平参差不齐，所面向的重点也不同，也许你花了大把时间弄懂的是一个错误的或者过时的知识。而大部分号称教你入门的文章，可能也就是告诉了你如何搭建一个运行环境，这门语言的精髓和重点作者自己估计也没弄明白。而如果你碰到一篇被奉为经典的好的入门文章，那你真的要好好感谢作者。因为这意味着作者付出了大量的深入思考，深入浅出这四个字说起来简单，做起来可是需要相当的功底的。相对较好的做法在这么多语言的学习过程中，我也总结了一些相对比较好的学习方法。我认为看代码是非常有必要的，因为光死记语法是无法掌握好这门语言的。但是去看一些大型项目代码的缺点我在上面也说了，到底该如何是好呢？我建议大家可以去看官方给出的，专门供初学者学习的 Step-By-Step 代码，这种代码一般在官方的文档页就可以找到链接入口，它有如下好处：由浅入深，富有层次。这些代码往往是跟随者文档的深入，慢慢把语法细节展开的。不会一下给你展现太多，让你无法 GET 到重点。每段代码都会有一个重点要表现的特性，这样看起来会一目了然。有质量保证。这些代码的撰写一般是官方人员负责，这可以在很大程度上保证准确性。更新及时。我们知道很多语言的细节是会随着版本的升级有所改变的，而很多网上的第三方文档往往缺乏维护，但官方文档一般都会同步更新。我建议大家一边看手册一边看代码，这样印象会更深刻。眼睛看了之后，我认为要尽快找一些好的例子来练手，不需要一上来就搞比较复杂的大型项目，也是由浅入深。这种练手项目去哪里找呢，很多语言的 tutorial 板块就是干这个的，做的比较完善的甚至还提供在线的教学体验环境，大家应该好好利用。写在最后这篇讨论学习方法的文章引发了我的一些额外思考。我经常在开发者社区里看到老鸟和初学者互怼，写这篇文章的过程也让我理性思考了产生这些矛盾的原因。总的来说就是一些信息的不对称造成的。老鸟认为这个问题根本不是问题，网上一搜一大把，不愿多讲甚至冷嘲热讽。而初学者却觉得这些信息根本理解不能，老鸟的嘲讽就是一种羞辱。我认为要打破这种不对称需要双方付出耐心，而这种耐心的付出是相互的，你付出的多回报的就越多。而最先迈出付出这一步的，应该是初学者，毕竟从情理上来说是你请求人家办事。而你需要付出的不过是把自己的问题讲明白，说出你的思考过程，附上必要的信息。一个好学的人是不会让人讨厌的，但前提是你得有一个不让人讨厌的姿态展现出来。文章来源：https://joyqi.com/develop/how-to-learn-a-programming-language.html
AI摘要 本文介绍了在CentOS7环境下，使用宝塔面板搭建Gogs私人Git仓库的详细步骤。包括安装宝塔面板、Git、创建git用户组和用户、下载和解压Gogs安装包、启动安装程序、配置域名访问等。同时提供了gogs.service服务配置文件的示例，以便实现Gogs的开机自启。 document.addEventListener('DOMContentLoaded', function() { const urlDisplay = document.getElementById('urlDisplay'); urlDisplay.textContent = "此内容根据文章生成，更内容请访问：" + window.location.href; }); 安装文档 https://gogs.io/docs/installation我这里的安装环境:CentOS7 + 宝塔面板 + Nginx + Mysql5.7git 版本 1.8.3.1Gogs 版本 0.11.66 @ 2018-09-16安装包下载地址列表:官方:https://gogs.io/docs/installation/install_from_binary.htmlgithubhttps://github.com/gogs/gogs/releases找到 Linux amd64 的下载地址https://dl.gogs.io/0.11.66/gogs_0.11.66_linux_amd64.zip安装宝塔面板**yum install -y wget && wget -O install.sh http://download.bt.cn/install/install.sh && sh install.sh我这里选择的环境是Mysql5.7 + PHP7.2 + Nginx 1.14.0 + phpmyadmin4.x + Pure-Ftpd 1.0.47安装Git (已经安装的跳过)**yum install -y git查看Git版本**git --version创建一个git用户组**groupadd git创建一个git用户并添加到git用户组**useradd -g git git修改git用户的密码**passwd git创建好了之后, 切换到Git身份**su git这时候已经是git用户了, 进入git的home目录**cd ~下载gogs安装压缩包, 双引号里的下载地址替换为官方最新版本的下载地址**wget -c "https://dl.gogs.io/0.11.66/gogs_0.11.66_linux_amd64.zip" -O gogs.zip解压安装包**unzip gogs.zip进入gogs目录**cd gogs启动安装程序**./gogs web在宝塔面板->安全-> 添加3000端口, 允许访问回到桌面, 用浏览器打开安装向导页面, 根据自己情况设置**http://192.168.1.101:3000安装完成后, 回到终端, 退出当前的git用户**exit为gogs添加服务,开机启动**# 创建服务配置文件 vim /lib/systemd/system/gogs.service加入以下内容, 保存退出：**[Unit] Description=Gogs After=syslog.target After=network.target After=mysqld.service [Service] # Modify these two values and uncomment them if you have # repos with lots of files and get an HTTP error 500 because # of that ### #LimitMEMLOCK=infinity #LimitNOFILE=65535 Type=simple User=git Group=git WorkingDirectory=/home/git/gogs ExecStart=/home/git/gogs/gogs web Restart=always Environment=USER=git HOME=/home/git [Install] WantedBy=multi-user.target设置开机启动**systemctl enable gogs.service并手动启动服务**systemctl start gogs查看服务状态**systemctl status gogs在宝塔面板上配置域名访问(反向代理)这个时候就可以通过域名访问了, https证书在宝塔界面配置部署即可, 不用改gogs配置使用域名访问搭建好的gogs
AI摘要 本文介绍了在Centos7系统下安装Golang的步骤，包括下载安装包、解压到指定目录、配置环境变量等。通过这些步骤，用户可以成功安装并配置Golang环境。 document.addEventListener('DOMContentLoaded', function() { const urlDisplay = document.getElementById('urlDisplay'); urlDisplay.textContent = "此内容根据文章生成，更内容请访问：" + window.location.href; }); 1.下载安装包下载地址:https://studygolang.com/dl本次下载 go1.14.1.linux-amd64.tar.gzwget https://studygolang.com/dl/golang/go1.14.1.linux-amd64.tar.gz2. 解压到指定目录tar -C /usr/local -xzf go1.14.1.linux-amd64.tar.gz解压后在目录 /usr/local/go中3. 配置环境变量设置GOPATH 目录mkdir -p /home/gocodego命令依赖一个重要的环境变量：$GOPATHGOPATH允许多个目录，当有多个目录时，请注意分隔符，多个目录的时候Windows是分号;，Linux系统是冒号:当有多个GOPATH时默认将go get获取的包存放在第一个目录下$GOPATH目录约定有三个子目录src存放源代码(比如：.go .c .h .s等)pkg编译时生成的中间文件（比如：.a）bin编译后生成的可执行文件（为了方便，可以把此目录加入到 PATH变量中，如果有多个gopath，那么使用PATH变量中，如果有多个gopath，那么使用{GOPATH//://bin:}/bin添加所有的bin目录）编辑环境vim /etc/profile在最后一行加入 按i插入export GOROOT=/usr/local/go #设置为go安装的路径 export GOPATH=/home/gocode #默认安装包的路径 export PATH=PATH:GOROOT/bin:$GOPATH/bin按esc退出插入模式 :wq!强制保存退出vim命令编辑模式命令如下:q 不保存退出:q! 不保存强制退出:wq 保存退出，w表示写入，不论是否修改，都会更改时间戳:x 保存退出，如果内容未改，不会更改时间戳保存后执行 使环境生效source /etc/profile
AI摘要 本文强调苦难和不幸是人生的一部分，但它们也是成功的垫脚石。通过凡高和稻盛和夫的例子，文章说明了面对困难时，积极的态度和努力可以转化为成功。心理学家威廉汤姆斯的观点也被引用，强调个人对苦难的看法和态度决定了结果。文章鼓励读者以积极的心态面对挑战，将不幸视为成功的机遇。 document.addEventListener('DOMContentLoaded', function() { const urlDisplay = document.getElementById('urlDisplay'); urlDisplay.textContent = "此内容根据文章生成，更内容请访问：" + window.location.href; }); 人生悟语：苦难是一只驶向成功的船，当风暴来临时，别害怕，扬起帆，直面那滔天人海浪、搏击那汹涌的激流吧。人生不如意事十之八九。生活本是一种承受，人若学会正确对待不幸，那么你所遭受的也许正是你的福气，稻盛和夫曾说过，乍看的不幸，实际是幸事。看过著名油画大师凡高故居的人都知道，那里有的只是张裂开的木床和破皮鞋。凡高一生潦倒困苦，没有娶妻，但也许是生活的困窘，帮他完成了在艺术上的壮举，使他成为大师中的大师，使他的作品成为经典中的经典。就人生而言，不幸是个不请自来的不速之客。不幸是根弹簧，我们若向它屈服了，它反而使我们落魄潦倒，甚至在绝望和恐惧中逼迫我们一步步靠近灭亡；如果我们不臣服于它，反而会变得更坚强更勇敢。世界上没有完美无缺的东西，不幸便是人生完璧中的瑕疵。其实不完美才是一种美，在不断的争取中，不断地承受失败与挫折时，才能发现快乐。稻盛和夫青年时代，曾经在没有选择的情况下进入了当时一个很不景气的公司上班，拖欠工资是家常便饭，他也曾为此失落过，然而，就在那样一种环境下，稻盛倾注心血在实验研究上，取得了一个又一个可喜的成果。他对工作的态度也有了180度的大转弯，从厌恶到喜爱，这为他日后的成功打下了基础。风雨对于温室里的花朵而言绝对是灭顶之灾，不幸对于幸运儿而言无疑是致命的打击，毫无力量去抗拒迎击。因为幸运儿习惯了没有挫折和不幸的苦涩人生，在他们的生活中只有一帆风顺、心想事成，他们的字典里没有别有深味的“不幸”二字，而那些经常遭受不幸的人来说，他们的意志品质都是非常坚强的。他们深刻地明白，风调雨顺、风和日丽只是偶然光临，暴风骤雨、电闪雷鸣才是人生的常客。著名心理学家威廉汤姆斯说过，我们所谓的不幸和苦难，很大的程序上，要归结于个人对现象所持的看法。更重要的则是，一个人以什么样的心情与态度来面对和处理这些难题，最后的结果是迥然不同的。因此，我们不难发觉，即使是出于同样的环境和状态，有人认为是不幸和苦难，有人却认为这是千载难逢的良机与顺境。成功的人为什么能成功？因为对他们来说，每一个因素都是成功的良机，甚至包括不幸，不管身处何处，他们都会以积极、自信与乐观的态度去努力、去积淀自己，他们是奇迹的创造者。与此相反，另一些人持有消极与失败的心态，不愿意承担不幸，这样的人注定一辈子要潦倒。不同的心态，做出的不同的反应致使事情的结果截然相反。因此遇到任何挫折或打击时，千万不要呼天抢地，要微笑着告诉自己那是造化的考验。高尔基曾把苦难比作大学，几乎所有的成功人士都是从不幸中毕业的，不幸教给你坚强勇敢，更教会你拼博向上，这也是正如稻盛和夫指出的那样，苦难是一只驶向成功的船，当风暴来临时，别害怕，扬起帆，直面那滔天的海浪，博击那汹涌的激流吧。
【通俗版】宽带网络公司是如何进行网络计费的？
AI摘要 宽带网络公司通过拉线、开通账号密码、PPPOE拨号等方式为用户提供网络服务。BOSS系统是网络公司的核心，包括CRM、认证计费等。计费系统多基于FreeRadius修改，第一梯队公司如亚信、中兴软创、东软等，主要服务电信运营商；第二梯队如萨莫尔等，服务二级民营运营商。轻武计费认证系统（KDBOSS）主要针对中小型企业，支持多业务受理，历经16年发展，是宽带运营的重要管理软件。 document.addEventListener('DOMContentLoaded', function() { const urlDisplay = document.getElementById('urlDisplay'); urlDisplay.textContent = "此内容根据文章生成，更内容请访问：" + window.location.href; }); 从最近15年国内网络发展看，从最初的赶猫上网到VDSL、ADSL，再到光纤上网，网速得到了极大的提升，我们的网络生活也更加丰富，在线视频、网络下载、游戏、在线教育、网络会议、在线办公等等，特别是在今年疫情期间，我国的网络基础环境经受住了前所未来的考验，因为有了网络，即使家里蹲我们的生活也没有受到多少影响。得益于网络基础构架的完成、智能手机的普及、互联网各行业也开始蓬勃发展。宽带网络公司是如何运作的呢？当我们需要宽带接入的时候，网络公司会拉一条线路到家里（光纤小区是通过光纤进入用户家里，再通过光猫数据转换后进行上网，广电网络是通过电视数字信息线路上网，还有一种就是通过楼道的宽带接入盒，接入一根网线到用户家里），线路接通之后，网络公司开通帐号和密码，用户通过帐号密码进行PPPOE拨号上网。技术解释：网络公司在BOSS里创建了用户帐号，缴费后更新用户到期时间，当用户拨号时，消息首先到达BASE设备（如果华为的ME60，SE8000等BASE设备进行PPPOE协议通讯），然后再通过AAA认证（也有叫Radius认证）检查帐号密码是否匹配，检查用户是否到期等，通过之后下发宽带属性到BASE设备（就是是下载速度、上传速度信息），验证通过后即可上网。BOSS系统是什么？BOSS系统是网络公司最重要的系统之一，主要包括BSS和OSS两大块，按通俗的语言讲主要是客户资料管理系统（CRM），认证计费（Radius系统），还有工单系统、呼叫系统、缴费系统、业务受理系统、资源管理系统等等。计费系统如何选择？大多数计费系统都是FreeRadius修改而来，像网上有不少做一体系统的，大多数是按用户许可收费，一般支持能力在1万用户以内，属于三流计费系统。第一梯队做计费系统的公司：如亚信、中兴软创、东软等，主要客户是中国电信、中国移动、中国联通，管理用户在1000万以上。第二楼队：萨莫尔等，主要客户是二级民营运营商，如长城宽带、宽度网络、艾普网络。管理用户在500万以内。宽带运营中，用户计费只是整体体系中最重要的一块，其实还包括了运营支撑，如用户开通、缴费、故障处理、客服系统、电销系统等。轻武计费认证系统如何？轻武计费认证系统（KDBOSS）主要针对中小型企业，用户规模在1-100万内的小区宽带运营商，本系统可作为宽带运营支撑系统，同时该系统支持多业务受理，包括宽带业务，商业客户，语音业务，增值业务等。本系统历经16年千锤百炼，历经百万宽带用户的洗礼，一体化解决方案是一款宽带运营必不少的管理软件。下载：轻武计费主证系统介绍上线城市
文章强调了即使出身贫穷，通过勤奋和努力也能改变命运，成为富一代。作者分享了自己因贫穷而产生的自卑和炫耀心理，提醒人们要不断学习，提高自己的才德和心理修养，保持低调，戒骄戒躁。[...]
本文提供了一个详细的教程，指导读者如何搭建Android开发环境，包括下载和安装JDK、Eclipse和Android SDK，以及在Eclipse中配置Android开发插件和SDK。文章还介绍了如何新建AVD（Android虚拟设备）和Android项目，并测试项目运行。作者建议使用SDK升级工...[...]