大成都5条新线车站齐亮相!

该日志由 samool 发表于 2020-12-07 19:50:37

就在今天!!!备受关注的5线6项目车站集体“闪亮登场”!5条新线串联成都多个区域,站厅设计也囊括了科技华章、音乐地铁、锦绣芳华、水育柳城等多元风格,将沿线特色融入厅站风貌,用轨道交通串联天府文化!

6号线一二三期

主题:“科技华章、创新菁蓉”

6号线根据站点周边文化定位全线站点,共设两个层级,其中一般艺术站45座(不含西博城站和西北桥站),重点艺术站9座。

9座重点艺术站

望丛祠站、金府站、西南交大站、建设北路站、牛王庙站、三官堂站、金融城东站、秦皇寺站、天府商务区站。

01望丛祠站

以“望丛二帝”为主题,灵感源自都江堰的地势水形及成都平原综合交错的自然形态,通过深色的天花格栅和不同层次的绿色片状金属板以表达自然形态中“水与田”的元素。

02金府站

以“青春活力”为主题,灵感源于紧邻的欢乐谷过山车等游乐设施的曲线造型,通过优美的曲线造型和流光溢彩的色带,表达欢快和动感的游乐气氛。运用鲜明的色彩对比,展现出一个梦幻的世界。

03西南交大站

以“天堑变通途”为主题,提炼了西南交大象征性的桥梁、隧道、大门的拱形元素作为空间构成的基础要素,以表达“传承、纪念、学术、探索”的主旨;车站艺术品名为“天堑变通途”。

04建设北路站

以“时光穿梭”为主题,营造科技、未来的空间气质,通过深色的天花背景和线性格栅、灯具,形成明暗对比强烈的震撼的视觉感受,整个地铁站成为链接川蜀工业过去与未来的“时空虫洞”。

05牛王庙站

以“市井牛王庙”为主题,从老的历史街区场景中提取元素,经过现代手法的演绎,形成一种穿越时空、传统与现代再次对话的独特空间,使人们再次体验到昔日散发浓厚酒文化的市井场景,感受成都老街巷的独特魅力。

06三官堂站

以“成都工业文明”为主题,提取自四川机械总局旧址建筑的元素,通过回应拱券的造型,使用木纹格栅和混凝土饰面材料,展示出“工业、高大,张力、厚重”的历史感,经过现代手法的演绎,形成一种穿越时空、传统与现代再次对话的独特空间。

07金融城东站

以“科技金融创新”为主题,通过对可视化的“金融数据”及代表科技核心的“芯片电路”提取动感、强劲的线性元素,并以白色金属为基底,金、银作为点缀性主题色,赋予金融城东站时尚、科技的空间特征。

08天府商务区站

以“科技创新·AI智能”为主题,提取“人工智能虚拟大脑”的三角形元素,通过重复连续的设计手法,将整个车站空间联系起来,塑造出形式统一并富有变化的多维空间。

09秦皇寺站

以“科技创新·互联共享”为主题,将抽象的“互联网”、具象的“川西竹编”两种元素相融合,这是刚与柔的碰撞,形与光的契合。体现科技与传统的交织,传达出互联网共享与文化传承欣欣向荣的发展意向。

45座一般艺术站

6号线一二期工程一般艺术站根据区位,共划分为三个段落,从望丛祠站到西华大道站,为“先进制造业集中、复合型产学研新城”的高新西区展现出“青春创业活力”的文化个性;从金府站到琉三路站,为“历史悠久、文化商业活力强盛”的主城区段展现出“历史科技华章”的人文情怀;从金石路站到观东站,为“现代商务中心、高端产业新城”的高新南区能展现出“时代科技创新”的艺术格调。三期工程整体空间着重于功能性、舒适性,采用空间一体化打造手法,通过将天花、墙面相连,统一设计打造,使整个车站空间浑然一体,塑造出具有“科技感”的空间氛围。

8号线一期

主题:“音乐地铁,国际文创”

8号线一期所经区域覆盖众多教育、音乐及文创产业,故将“音乐地铁,国际文创”作为本线路设计主题,以文创方式多维表现音乐主题的地铁空间,个性鲜明,独具特色。

5座重点艺术站

川大江安校区站、芳草街站、川大望江校区站、东郊记忆站、理工大学站。

01川大江安校区站

以“风华正茂”为设计主题,将展开的“书本”作为空间延展的主体装饰构造,“书页”片状的组合形式活泼、清逸,通过冰蓝色灯光的渲染,形象的展现川大新校区现代、朝气的精神风貌和活力。

02芳草街站

以“玉林百态”为设计主题,提取玉林片区街景风貌的特点,以绿色为基调,通过对金属材料的镂空处理,将空间营造出树影婆娑的质感,空间极富张力,宁静而惬意,与玉林片区的生活及人文内涵相得益彰,将为乘客提供别样的车站空间体验。

03川大望江校区站

以“人文百年”为设计主题,从校区建筑群落中寻找历史印记,对空间形式、质感、色彩进行一定程度的还原表达。穹顶形式的应用,书卷展开的风雅,整体空间沉稳、庄重,各个细节共同勾勒出川大百年厚重的历史沉淀与精神内涵。

04东郊记忆站

以“工业新音”为设计主题,空间运用充满力量感的“工业化”形象色彩、肌理进行打造,构成方式主要为线性表现,并结合充满律动的灯光、生动的多媒体艺术品表现,让乘客穿梭于时间与光影的空间氛围里,工业的辉煌未有失色,更替的是对文化创造的无限热情。

05理工大学站

以“蜀地绝响”为设计主题,将理工大学地质、能源等教育科研领域的特色作为创作出发点,以风蚀地貌的概念进行空间构筑,日月星辰下蜿蜒曲折的空间形态浑然天成,换乘区域通过富有象征性的“生物化石”天花构成进行过渡,强调空间聚合力和次序感。

20座标准艺术站

通过音乐文化因素和站域特点的相互叠加,形成两个分段线路文化篇章,分别是“西洋律动”“传统国韵”。通过两个篇章的文化点、线表达,更加立体的呈现了以音乐作为主题打造的8号线一期独有的文化气质和内涵。

9号线一期

主题:“锦绣芳华,绿裳画图”

9号线一期工程将城市的优雅之美和古典之美以空间一体化的设计手法进行打造,以蜀川胜概为底图,用蜀锦蜀绣的编织纹路演绎,描绘成都山、水、田、林、城构筑的公园城市,寻找成都的繁华与秀丽,领略这座城市独有的风姿,感悟博大精深源远流长的天府文化。

4座重点艺术站

孵化园站、锦城大道站、簇桥站和机投桥站。

01孵化园站

以“科技创新”为设计主题,用“折线”三维元素将空间、灯具、综合末端一体化打造,创造具有科技未来感、同时又契合“创业天府”文化定位的艺术空间。整体造型嵌入多媒体艺术装置,增加趣味性和互动性,展现科技无限的遐想,实现艺术空间一体化。

02锦城大道站

以“锦绣蓉城”为设计主题,提取市花“芙蓉”,运用到柱子进行一体化设计,柱子之间形成一条贯穿站厅的廊道,营造生态自然的氛围,将成都的生态文化融入站点设计,体现成都人民休闲生活慢行的状态。

03簇桥站

设计灵感来自传统的“养蚕缫丝”场景,将“蚕茧”“蚕簇”和“生丝”的故事线融入车站空间之中。墙柱面造型融合桑树形态,进行空间一体化设计,艺术灯具表达蚕茧连着蚕丝缠绕桑树交错的画面,灵动的展现了“养蚕缫丝”的画面感。

04机投桥站

以“织锦文化”为设计主题,以织锦垂挂的自然形态为造型元素,搭配织锦的华丽色彩,模拟蜀锦织造基地织布垂挂的场景,将织造的美感大胆与传统建筑进行拼接,形成独特的时空对话,体现了“蜀锦历史名镇”的风采,展现了锦绣芳华的工艺之美。

9座一般艺术站

分别为金融城东站、心岛站、三元站、太平寺站、华兴站、武青南站、培风站、成都西站、黄田坝站。以“巴蜀锦绣、魂之凝结”为基石对蜀锦蜀绣文化最具代表图案“芙蓉”进行结构提炼,重组转化为抽象的元素在空间进行一体化表达,使整个车站形成一个富有独特文化气质的空间。同时,在局部巧妙地将蜀锦蜀绣形态融入地域文化,用蜀锦蜀绣的编织纹路展现了川西林盘、秀丽锦江之美。

17号线一期

主题:“水育柳城,丝织锦绣”

17号线一期工程以“水润天府,生态成都”和“浮光掠影,记忆成都”为设计理念。在生态线路段中提取自然的秀丽形态与历史的文昌古韵,表达天府之都在水文化孕育下的生态与健康,通过河流的形式变化与自然形态的提取元素贯穿整条线路。

2座重点艺术站

凤溪河站和机投桥站。

01凤溪河站

以水为引,以生态为线,利用站内层高的优势,打造出一个视野宽广的空间。天花以流动的水为元素,从天花衍生到柱面,使顶面与立面贯通,如大河之水顺流而下。凤溪河站艺术品展现了逾三千年的古蜀国历史悠久,其灿烂的文明在华夏历史独树一帜。

02机投桥站

机投桥站以“花楼织锦”作为设计理念,将传统蜀锦织布机和传统建筑作为空间的创作起点,天花流畅的线条结合人字坡传统形态,仿佛布匹织锦的韵律贯穿整体空间,并在空间局部延展至墙面,承载此站点的文化主题,合力发扬传统工艺的工匠魅力,延续历史空间记忆。

7个标准站

分别为金星站、黄石站、市五医院站、温泉大道站、明光站、九江北站、白佛桥站,按位置分为“水历史”“水生态”“成都记忆”三个区段,设计思路上延续了以“水”元素为主导,并提取绿蓝黄三个色系串联整条线路的标准站概念主题。站厅装修以白色调为主,从端墙两侧倒角弧板,通过一层一层的圆通弧线穿插。将水的韵律从两侧向中间流动。

18号线:福田站

福田高架站外立面整体以前卫的航空器造型,辅以极具速度感的条窗呈现一幅翱翔腾飞的姿态,预示着空港新区繁荣发展的美好愿景。

车站内部全段以机舱为设计主题,经由机舱窗口的造型,延伸出透过窗口看天府的设计概念。

成都轨道交通将坚持以“璀璨巴蜀,活力天府”为主旨,以“世界级的地下文化走廊、国际范的天府文化名片、蜀都韵的流动博物馆”为目标,按照一线多景的设计思路,彰显成都世界文化艺术名城的气息。

该日志标签: 成都, 音乐, 目标, 生活, 元素, 还原, 地铁, 城市, 历史, 桥梁, 休闲, 风采, 风格, 文化, 世界, 设计, 博物馆, 工业, 四川, 智能, 链接, 公园, 背景, 主题, 魅力, 对话, 故事, 都江堰, 段落, 创业, , 数据, 时间, 共享, 特点, 细节, 特征, 商业, 空间, 天府, 天花

马云最新演讲全文2020-9-30

该日志由 samool 发表于 2020-09-30 12:04:48

2020年非常特殊,未来一定是一段历史的分水岭;海南成为自贸港,也必定是一个历史性的选择;我希望我们CEC这次的海南会议,也能成为一个跨越时代的会议,在疫情之后,新的全球化开始之后,在整个数字时代到来的时候,我们CEC的企业家能够在这段历史中创造独特的价值。

我昨天还在武汉,也和我们CEC的三十几位理事一起,到武汉去了一趟。几个月前在电视里看武汉,确实非常之难,这次到武汉,真的感到武汉是一座英雄的城市,有英雄气质。疫情是结束了,我们该考虑如何让经济重生。经济重生不是为了回到昨天、回到以前,而是在更高的水平上面,从疫情中看到未来,看到趋势,把握机会。

这次从武汉来到海南,这里面我觉得是巧合,好像也有一种必然的东西。两年前,习主席宣布了建设海南自贸港,全面开放的战略,两年过去了,世界格局发生了巨大的变化。但是我依然相信,我们必须要坚持开放,必须要坚持全球化,特别是疫情之后,我相信全世界所有的门都是要靠自己去打开的,没有门是天然开着的,这时候坚持全球化比什么时候都重要、都有意义。现在海南就站在一个新的历史的起点上,自贸港建设不是简单的海南发展的机遇,更不仅仅是中国经济发展的一个机遇,而是要担当起为世界探索新的全球化的历史责任。

我自己觉得,国际化和全球化是两个不同的概念,国际化更偏向于中国人跟外国人做生意,是双边为主。而全球化是世界各国的大事情,是一个全局的问题。今天很多人觉得全球化出现了这样那样的问题,而我并不这么认为:

第一,我认为今天是真正全球化开始的时候。昨天的、原来的、传统的、工业时代的全球化正在终结。新的、真正的、数字时代的全球化才刚刚打开。

以前,全球化是发达国家和大企业主导,未来,全球化应该是发展中国家、中小企业走向世界;以前贸易是全球化的主力,未来科技将是全球化的主力;以前是人在流动、货在流动,未来是数据在流动、服务在流动;以前是传统企业的全球化,未来是用好互联网技术的企业的全球化;未来,任何一个人,只要有一部手机就可以做全球生意,未来所有的中小企业都是跨国公司,过去三十年是6000家大企业决定了全球化,未来应该是6000万家中小企业决定全球化。地域的扩大就是业务的扩张,这是世界给予我们的巨大机会。

第二, 这是由中国内需驱动的新一轮全球化。

新一轮的全球化,中国将会从“卖卖卖”,变成“买买买”。海南自由贸易港有自己的历史使命,海南未来留在历史中将会成为一个非常重要的角色。假设我们对贸易游戏规则不满意,今天给了我们一次机会,我们是否有这种胸怀、有这种格局、有这种担当为世界未来数字的全球化,为更多企业、更多国家、更多发展中国家的全球化,来制定一个更加公平、可持续、绿色的贸易规则?大家其实不用害怕从“卖卖卖”变成“买买买”。中国每一次大门打开,都是中国进步的象征,每一次大门打开,中国都进步了。

我们要不断地走出去。我记得我们以前的人走出去是找差距,我们觉得人家这个做得好、那个做得好。今天我们很多中国企业走出去,或者很多中国人走出去,是在找感觉。当我们在找感觉的时候,其实我们正在退步。

上一次全球化,是美国3亿人消费驱动的;中国这次的全球化是14亿人的内需,会驱动下一轮真正的全球化,带动世界经济。进口不是终点,进口最终是要倒逼中国产业提升、消费升级,促进现代服务业的发展。对于企业家来说,未来的机会在中国那些百万人口的小城镇。我不知道大家是否知道中国有多少城市过100万人口,我在2014年初步做了一个统计,美国大概有不到12个城市过100万人口,中国有167个城市过100万人口。而100万人口的基础建设、100万人口所诞生的巨大产业,我们远远没有发展好。这些近百万城市的人口,也许我们将来会有三百个,这些地方会迸发出巨大的消费潜力。内需绝对不是有钱人的拉动,内需应该是满足每一个普通百姓的需求,普通人的内需拉动,才是真正可以持续发展的内需价值。

第三,新的全球化是一种服务世界的能力。

全球化的核心是在其他国家和地区创造价值,创造就业,去做当地做不到的事情。如果说过去中国走出去,必须要人走出去、机器走出去、资金走出去;今天的中国走出去需要信息走出去、服务走出去、价值走出去。全球化是一种服务世界的能力,不是赚世界钱的能力。中国企业应当坚定地走向全球,而不是去征服全球。很多人爬山,自己认为是去征服自然,但自然不是去征服的,自然应该是去臣服的,对于世界真正的价值,不是远征,而是去创造价值。我们走出去要赢回来的不仅仅是利润,更应该赢回来的是尊重;我们要展示的不是一个强大的国家,而是一个善良美好的国家;我们不想去转移过剩产能,而是要到当地创造新的、不同的价值,尊重当地的文化、尊重当地的价值观、尊重当地的宗教和信仰、尊重每个国家不同的机制和体制。我们要相信这个世界因为不同而美好。都像你一样,也不行,都像别人一样,也不行。

2020年应该说是一个转折之年,我和很多企业家探讨,发现大家或多或少都有点焦虑。其实谁都有焦虑,任何时代、任何企业、任何人都有焦虑,只是有的人敏感一些,有的人不敏感。我对未来的判断:远的一定好,近期很困难,中期更困难。现在是飞机穿过云层的颠簸期,所以大家要把握好方向盘,系好安全带,但最重要的是要有未来观,当你从未来看今天的时候,今天的困难不是困难,当你只看着今天,跟昨天比较的时候,你的沮丧会越来越大。所以我们要面向未来,用未来的方法来解决今天的问题,而不要用昨天的方法来解决今天的问题。很多人非常乐观,很多人又非常悲观,我认为过度乐观、过度悲观都是因为没有看清楚未来。

昨天的看法和行动决定了你企业的今天,而今天的看法和思考又决定了你企业的明天。未来不是指两年以后你会什么样,未来是指二十年以后、三十年以后,你的企业会变成什么样。在座每个企业,你们今天的规模、你们今天的成就,我们今天所取得的一切不是今天做的,都是因为二十年以前我们相信中国会有今天。我相信当你从今天去判断二十年以后这个世界会变成怎么样,社会会变成怎么样,去解决未来的问题,相信年轻人,你一定会有前途。

在今天所有巨大的不确定当中,我认为数字化是确定的,数字化一定会全面改造所有的行业。不是每家企业都要转型,但是每个企业都必须升级,完成数字化升级。现在不要担心跟你竞争了二十年、十年的“老王”,你要担心的是那些你完全不认识、没见过到的 “小李”,这批人从来没出现过,他们没有包袱,他们采用新的技术,敢于创新,敢于用互联网。这些年轻人将是中国的希望,但也可能是在座每个人可能碰上的压力,最后打败各位的不是互联网企业,而是用好互联网技术的企业。我希望所有的企业今天一定要思考,要利用数据化来升级自己的管理、升级自己的组织、升级自己的产品。

未来十年,是传统行业推进数字化的最后十年。其实我在二十年前,在我去过的很多的省份,不断在讲互联网对于零售行业的冲击、对制造行业的冲击,大家并没有当回事情,直到淘宝、天猫、阿里巴巴、百度这些企业、腾讯这些企业起来以后,大家突然觉得“狼”来了,其实“狼”一直都在。

如果今天不准备变革,十年后我相信你一定是数字脱贫的对象。直到今天,很遗憾的是,还有很多企业家依然在讲数字革命是一场危言耸听,数字技术、互联网技术只是简单的工具。我想告诉大家,数字技术将重新定义生产制造,重新定义零售,重新定义技术,重新定义生产资料和一切,甚至很快这个技术将会引发全社会的所有生产关系的变革。

其实未来越是距离技术远的行业,越是还没有被技术改造的行业,机会越大。很多企业其实只要投入更多技术,在人才,在理念上多一点点,获得的收益和价值将是非常确定的。今天你纯粹做一家互联网公司,你未必有回报,但是你今天把自己传统企业变成数字化,你的回报是肯定的。

传统行业的数字化转型关键在于观念,关键在于理念,责任一定在一把手身上,责任不在技术部门,一把手不改变的企业一定不是有远见,有担当的企业。

疫情总会结束,但是新冠这种疾病可能会伴随人类几百年甚至上千年,现在这个病毒恐怕是会比我们谁都活得长,我们要学会适应,我们的防疫也要学会从常规防疫变成常态防疫,也许以后绝大部分的医院都有一个“新冠科”,这是长期共存可能会出现的情况。

2020年注定是改变历史的一年,在武汉的时候,我们CEC的企业家们给自己提了这样的要求:企业家不等于有钱人,有钱人更不一定是企业家。企业家是国家、民族的优质资产,国难当头时,企业家们无须命令,自觉自愿,挺身而出。疫情是突发的灾难,我们必须主动担当;疫情结束以后的经济恢复,企业家更是责无旁贷。

所有的企业,在座的企业家们,如果你的企业在十年、二十年内没有经历过三次、五次的灾难,你的企业永远是经不起打击的。越是在世界剧变的时候,越是在历史的转折点上,企业家越要担当,我们做这些事情,不是为了赢得掌声,不是为了赢得肯定,不是为了赢得一些政策的支持,而是我们内心相信、我们喜欢、我们认定,应该用未来的眼光,用战略的眼光,与世界去沟通,通过我们自己的努力,让这个世界变得越来越好。

该日志标签: 技术, 美国, 升级, 腾讯, 选择, 城市, 历史, 服务, 希望, 工具, 文化, 世界, 经济, 电视, 手机, 方法, 改造, 工业, 数字, 判断, 淘宝, 游戏, 英雄, 百度, 压力, 信息, 价值, 规则, 灾难, 阿里巴巴, 管理, 病毒, 问题, 数据, , 中国, 组织, 企业, 人才, 公司, 防疫, 消费, 时候, 数字化, 全球化, 企业家, 出去, 疫情

Golang 汇编入门知识总结

该日志由 samool 发表于 2020-09-27 14:35:04

作者:ivansli,腾讯 IEG 运营开发工程师

在深入学习 Golang 的 runtime 和标准库实现的时候发现,如果对 Golang 汇编没有一定了解的话,很难深入了解其底层实现机制。在这里整理总结了一份基础的 Golang 汇编入门知识,通过学习之后能够对其底层实现有一定的认识。

0. 为什么写本文

平时业务中一直使用 PHP 编写代码,但是一直对 Golang 比较感兴趣,闲暇、周末之余会看一些 Go 底层源码。

近日在分析 go 的某些特性底层功能实现时发现:有些又跟 runtime 运行时有关,而要掌握这一部分的话,有一道坎是绕不过去的,那就是 Go 汇编。索性就查阅了很多大佬们写的资料,在阅读之余整理总结了一下,并在这里分享给大家。

本文使用 Go 版本为 go1.14.1

1. 为什么需要汇编

众所周知,在计算机的世界里,只有 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 中有一句很经典的话:一切皆文件)。

那么,问题来了:

  1. 什么是程序?
  2. 什么是进程?

2.1 程序

维基百科告诉我们:程序是指一组指示计算机或其他具有消息处理能力设备每一步动作的指令,通常用某种程序设计语言编写,运行于某种目标体系结构上。

从某个层面来看,可以把程序分为静态程序、动态程序:静态程序:单纯的指具有一定格式的可执行二进制文件。动态程序:则是静态可执行程序文件被加载到内存之后的一种运行时模型(又称为进程)。

2.2 进程

首先,要知道的是,进程是分配系统资源的最小单位,线程(带有时间片的函数)是系统调度的最小单位。进程包含线程,线程所属于进程。

创建进程一般使用 fork 方法(通常会有个拉起程序,先 fork 自身生成一个子进程。然后,在该子进程中通过 exec 函数把对应程序加载进来,进而启动目标进程。当然,实际上要复杂得多),而创建线程则是使用 pthread 线程库。

以 32 位 Linux 操作系统为例,进程经典的虚拟内存结构模型如下图所示:

其中,有两处结构是静态程序所不具有的,那就是 运行时堆(heap)运行时栈(stack)

运行时堆从低地址向高地址增长,申请的内存空间需要程序员自己或者由 GC 释放。运行时栈从高地址向低地址增长,内存空间在当前栈桢调用结束之后自动释放(并不是清除其所占用内存中数据,而是通过栈顶指针 SP 的移动,来标识哪些内存是正在使用的)。

3. Go 汇编

对于 Go 编译器而言,其输出的结果是一种抽象可移植的汇编代码,这种汇编(Go 的汇编是基于 Plan9 的汇编)并不对应某种真实的硬件架构。Go 的汇编器会使用这种伪汇编,再为目标硬件生成具体的机器指令。

伪汇编这一个额外层可以带来很多好处,最主要的一点是方便将 Go 移植到新的架构上。

相关的信息可以参考 Rob PikeThe 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 symbols
FP(Frame pointer)arguments and locals
PC(Program counter)jumps and branches
SP(Stack pointer)top of stack
  • FP: 使用如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 传送到 AX
LEAQ传送地址传送LEAQ AX, BX // 把 AX 有效地址传送到 BX
PUSHQ传送栈压入PUSHQ AX // 将 AX 内容送入栈顶位置
POPQ传送栈弹出POPQ AX // 弹出栈顶数据后修改栈顶指针
ADDQ运算相加并赋值ADDQ BX, AX // 等价于 AX+=BX
SUBQ运算相减并赋值SUBQ BX, AX // 等价于 AX-=BX
CMPQ运算比较大小CMPQ SI CX // 比较 SI 和 CX 的大小
CALL转移调用函数CALL runtime.printnl(SB) // 发起调用
JMP转移无条件转移指令JMP 0x0185 //无条件转至 0x0185 地址处
JLS转移条件转移指令JLS 0x0185 //左边小于右边,则跳到 0x0185

4. 汇编分析

说了那么多,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-24

TEXT "".add TEXT 指令声明了 "".add 是 .text 代码段的一部分,并表明跟在这个声明后的是函数的函数体。在链接期,""这个空字符会被替换为当前的包名: 也就是说,"".add 在链接到二进制文件后会变成 main.add

(SB) SB 是一个虚拟的伪寄存器,保存静态基地址(static-base) 指针,即我们程序地址空间的开始地址。"".add(SB) 表明我们的符号位于某个固定的相对地址空间起始处的偏移位置 (最终是由链接器计算得到的)。换句话来讲,它有一个直接的绝对地址: 是一个全局的函数符号。

NOSPLIT: 向编译器表明不应该插入 stack-split 的用来检查栈需要扩张的前导指令。在我们 add 函数的这种情况下,编译器自己帮我们插入了这个标记: 它足够聪明地意识到,由于 add 没有任何局部变量且没有它自己的栈帧,所以一定不会超出当前的栈。不然,每次调用函数时,在这里执行栈检查就是完全浪费 CPU 时间了。

$0-16

24 指定了调用方传入的参数+返回值大小(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 的值,存到寄存器 AX
  • ADDQ "".b+32(SP), AX从 main 函数栈空间获取入参 b 的值,与寄存器 AX 中存储的 a 值相加,结果存到 AX。相当于 AX=a+b
  • MOVQ 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)    RET

Go 汇编实现为什么是 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,运行得到结果:5

5.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

通过上面操作,可知:

  1. (FP)伪寄存器,只有在编写 Go 汇编代码时使用。FP 伪寄存器指向 caller 传递给 callee 的第一个参数
  2. 使用 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 调试命令

  • run
  • continue
  • break
  • backtrace 与 frame
  • info break、locals
  • list 命令
  • print 和 ptype 命令
  • disass

除了 gdb,另外推荐一款 gdb 的增强版调试工具 cgdb

https://cgdb.github.io/

效果如下图所示,分两个窗口:上面显示源代码,下面是具体的命令行调试界面(跟 gdb 一样):

#### 6.2 delve 调试代码

delve 项目地址

https://github.com/go-delve/delve

带图形化界面的 dlv 项目地址

https://github.com/aarzilli/gdlv

dlv 的安装使用,这里不再做过多讲解,感兴趣的可以尝试一下。

  • 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

该日志标签: sp, 字符, 函数, 消息, 进程, 动作, 腾讯, 工作, 目标, 移动, 目录, 汇编, 系统, 静态, 驱动, 经典, ip, 工具, 错误, 世界, 内容, live, 文件, it, 设计, 开发, 方法, 程序, 运行, 数字, 宽度, 链接, 输入, 代码, 资料, c, 信息, bug, 域名, 问题, 命令, map, 数据, 时间, 保存, 运算, 工程师, 程序员, 环境, file, int, 特性, 细节, 参数, 变量, 指令, unicode, 内存, root, type, 调试, input, o, 运营, 缺点, 时候, 语法, 文档, 语言, main, add, 寄存器

【Redis持久化】服务器突然挂了!Redis缓存都在内存中啊

该日志由 samool 发表于 2020-09-27 14:29:53

我是Redis,一个叫Antirez的男人把我带到了这个世界上。

“快醒醒!快醒醒!”,隐隐约约,我听到有人在叫我。

慢慢睁开眼睛,原来旁边是MySQL大哥。

“我怎么睡着了?”

“嗨,你刚才是不是出现了错误,整个进程都崩溃了!害得一大堆查询请求都给我怼过来了!”,MySQL说到。

刚刚醒来,脑子还有点懵,MySQL大哥扶我起来继续工作。

“糟了!我之前缓存的数据全都不见了!”

“WTF?你没有做持久化吗?”,MySQL大哥一听脸色都变了。

我尴尬的摇了摇头,“我都是保存在内存中的,所以才那么快啊”

“那也可以在硬盘上保存一下啊,遇到这种情况全部从头再来建立缓存,这不浪费时间嘛!”

我点了点头,“让我琢磨一下,看看怎么做这个持久化”。

RDB持久化

没几天,我就拿出了一套方案:RDB

既然我的数据都在内存中存放着,最简单的就是遍历一遍把它们全都写入文件中。

为了节约空间,我定义了一个二进制的格式,把数据一条一条码在一起,生成了一个RDB文件。

不过我的数据量有点大,要是全部备份一次得花不少时间,所以不能太频繁的去做这事,要不然我不用干正事了,光花时间去备份了。

还有啊,要是一直没有写入操作,都是读取操作,那我也不用重复备份,浪费时间。

思来想去,我决定提供一个配置参数,既可以支持周期性备份,也可以避免做无用功。

就像这样:

  • save 900 1 # 900秒(15分钟)内有1个写入
  • save 300 10 # 300秒(5分钟)内有10个写入
  • save 60 10000 # 60秒(1分钟)内有10000个写入

多个条件可以组合使用,只要上面一个条件满足,我就会去进行备份。

后来我又想了一下,这样还是不行,我得fork出一个子进程去做这件事,不能浪费我的时间。

有了备份文件,下次我再遇到崩溃退出,甚至服务器断电罢工了,只要我的备份文件还在,我就能在启动的时候读取,快速恢复之前的状态啦!

MySQL:binlog

我带着这套方案,兴冲冲的拿给了MySQL大哥看了,期待他给我一些鼓励。

“老弟,你这个方案有点问题啊”,没想到,他竟给我浇了一盆冷水。

“问题?有什么问题?”

“你看啊,你这个周期性去备份,周期还是分钟级别的,你可知道咱们这服务每秒钟都要响应多少请求,像你这样不得丢失多少数据?”,MySQL语重心长的说到。

我一下有些气短了,“可是,这个备份一次要遍历全部数据,开销还是挺大的,不适合高频执行啊”

“谁叫你一次遍历全部数据了?来来来,我给你看个东西”,MySQL大哥把我带到了一个文件目录下:

  • mysql-bin.000001
  • mysql-bin.000002
  • mysql-bin.000003
  • ···

“看,这些是我的二进制日志binlog,你猜猜看里面都装了些什么?”,MySQL大哥指着这一堆文件说到。

我看了一眼,全是一堆二进制数据,这哪看得懂,我摇了摇头。

“这里面呀记录了我对数据执行更改的所有操作,像是INSERTUPDATEDELETE等等动作,等我要进行数据恢复的时候就可以派上大用场了”

听他这么一说,我一下来了灵感!告别了MySQL大哥,回去研究起新的方案来了。

AOF持久化

你们也知道,我也是基于命令式的,每天的工作就是响应业务程序发来的命令请求。

回来以后,我决定照葫芦画瓢,学着MySQL大哥的样子,把我执行的所有写入命令都记录下来,专门写入了一个文件,并给这种持久化方式也取了一个名字:AOF(Append Only File)

不过我遇到了RDB方案同样的问题,我该多久写一次文件呢?

我肯定不能每执行一条写入命令就记录到文件中,那会严重拖垮我的性能!我决定准备一个缓冲区,然后把要记录的命令先临时保存在这里,然后再择机写入文件,我把这个临时缓冲区叫做aof_buf

说干就干,我试了一下,竟然发现数据没有写入到文件中去。多方打听才知道,原来操作系统也有个缓存区,我写的数据被他缓存起来了,没有给我写入到文件中去,这不是坑爹呢嘛!

看来,我写完了还得要去刷新一下,把数据真正给写下去,思来想去,我还是提供一个参数,让业务程序去设置什么时候刷新吧。

appendfsync参数,三个取值:

  • always: 每个事件周期都同步刷新一次
  • everysec: 每一秒都同步刷新一次
  • no: 我只管写,让操作系统自己决定什么时候真正写入吧

AOF重写

这一次我不像之前那么冲动,我决定先试运行一段时间再去告诉MySQL大哥,免得又被他戳到软肋。

试用了一段时间,各方面都运行良好,不过我发现随着时间的推移,我写的这个AOF备份文件越来越大,越来越大!不仅非常占硬盘空间,复制移动,加载分析都非常的麻烦耗时。

我得想个办法把文件给压缩一下,我把这个过程叫做AOF重写

一开始,我打算去分析原来的AOF文件,然后将其中的冗余指令去掉,来给AOF文件瘦瘦身,不过我很快放弃了这个想法,这工作量实在太大了,分析起来也颇为麻烦,浪费很多精力跟时间。

原来的一条条记录这种方式实在是太笨了,数据改来改去,有很多中间状态都没用,我何不就把最终都数据状态记录下来就好了?

比如:

  • RPUSH name_list'编程技术宇宙'
  • RPUSH name_list'帅地玩编程'
  • RPUSH name_list'后端技术学堂'

可以合并成一条搞定:

  • RPUSH name_list '编程技术宇宙' '帅地玩编程' '后端技术学堂'

AOF文件重写的思路我是有了,不过这件事干起来还是很耗时间,我决定和RDB方式一样,fork出一个子进程来做这件事情。

谨慎如我,发现这样做之后,子进程在重写期间,我要是修改了数据,就会出现和重写的内容不一致的情况!MySQL大哥肯定会挑刺儿,我还得把这个漏洞给补上。

于是,我在之前的aof_buf之外,又准备了一个缓冲区:AOF重写缓冲区

从创建重写子进程开始的那一刻起,我把后面来的写入命令也copy一份写到这个重写缓冲区中,等到子进程重写AOF文件结束之后,我再把这个缓冲区中的命令写入到新的AOF文件中。

最后再重命名新的AOF文件,替换掉原来的那个臃肿不堪的大文件,终于大功告成!

再三确定我的思路没有问题之后,我带着新的方案再次找到了MySQL大哥,我都做到这份儿上了,这一次,想必他应该无话可说了吧?

MySQL大哥看了我的方案露出了满意的笑容,只是问了一个问题:

这AOF方案这么好了,RDB方案是不是可以不要了呢?

万万没想到,他居然问我这个问题,我竟陷入了沉思,你觉得我该怎么回答好呢?

彩蛋

“你怎么又崩溃了?”

“不好意思,又遇到bug了,不过不用担心,我现在可以快速恢复了!”

“那老崩溃也不是事儿啊,你只有一个实例太不可靠了,去找几个帮手吧!”

该日志标签: 技术, 进程, 查询, 动作, 工作, 目录, 错误, 日志, 漏洞, 世界, 内容, 文件, 程序, 运行, 实例, 男人, mysql, 编程, bug, 周期, 问题, 命令, 同步, 数据, 记录, 时间, 参数, 指令, 内存, 崩溃, , 时候, aof, 写入, 重写

如何评价视频博主给“狗不理”给差评,商家直接报警?

该日志由 samool 发表于 2020-09-13 17:27:46

狗不理包子是天津市中国传统风味小吃,始创于公元1858年(清朝咸丰年间),为“天津三绝”之首,是中华老字号之一。2011年11月,国务院公布了第三批国家级非物质文化遗产名录,“狗不理包子传统手工制作技艺”项目被列入其中。

日前,微博上一则探访狗不理包子北京王府井总店的视频引发关注。视频博主吐槽商家的酱肉包“感觉里面全是肥肉”“特别腻”,并称“100块钱两屉有点贵”。不仅如此,当他在店里试吃时,后厨还不断传出咳嗽声。

本来,这也就是顾客正常的“吐槽”行为。万万没想到,对此,涉事餐厅一度发布声明称已报警,将追究相关人员及机构的法律责任,后该声明及声明发布账号均被删除。据报道,视频发布者回应称,截至目前“没有接到警方的任何通知”。

狗不理包子(Go Believe/Goubuli steamed bun)是中国天津的一道闻名中外的传统小吃,该小吃以一道由面粉、猪肉等材料制作而成的小吃,其始创于公元1858年(清朝咸丰年间),至今有100多年历史,该小吃为“天津三绝”之首,是中华老字号之一。狗不理包子的面、馅选料精细,制作工艺严格,外形美观,特别是包子褶花匀称,每个包子都不少于15个褶  。

刚出笼的包子,鲜而不腻,清香适口。 狗不理包子以鲜肉包为主,兼有三鲜包、海鲜包、酱肉包、素包子等6大类、98个品种。2011年11月,国务院公布了第三批国家级非物质文化遗产名录,“狗不理包子传统手工制作技艺”项目被列入其中,是世界闻名的中华美食之一。

所有美食的幕后都蕴藏一个传奇故事,相传百年前,乳名狗子的14岁少年高贵友谋生学艺,三年后在南河岸支摊做起包子生意,他的包子口感柔软、鲜香不腻、形式菊花的包子引来百里人们赞不绝口。且高贵友只顾做包子,而忽略客人,久而久之就有了狗子卖包子不理人的戏称。

其实狗不理包子之所以有这么大的名气,还两位大人物的评价有关。

清朝民国年间,作为吃遍天下美食界的大人物——慈禧太后,对狗不理包子也是赞不绝口。当年,袁世凯把狗不理包子呈现慈禧的时候,慈禧尝后就当着众人,大赞狗不理包子,甚至直接扬言称“真的是太好吃了”。狗不理包子也便因此得到了非常的名声,当然,除了慈禧太后,毛主席也品尝过这个狗不理包子,对它的味道赞不绝口。

那么,作为百年老字号“狗不理”包子,如今又是怎样呢?

一些吃过“狗不理”包子的网友都表示,狗不理包子现在是格外的膨胀,已经脱离了日常美食!我们大家都知道,包子再怎么说也是一种普通的食物,但如今狗不理包子的价格几乎已经可以和海参鲍鱼媲美了,这也是让很多人感到离谱的地方。对于一些曾经忠于狗不理包子的网友也表示,而且虽然狗不理包子是百年老字号,但包子的花样也越来越多,与传统越走越远,价格也是一路飙升,甚至不值得去吃。

很多人听到价格都觉得偏高,如果说包子的味道还是传统的老味道,而被卖到这个价格,估计吃的人也不会有太多的抱怨,天津狗不理包子的名气也会维持的很好,不像现在很多人一提到狗不理包子,都会一副“算了”的态度,可见不好吃而又偏贵的狗不理包子已经伤透了吃客的心了。如果想品尝天津老味包子的可以去老幼乐、石头门槛、老永胜、张记、老城里二姑,这几个老字号的包子铺。

但是最近几年狗不理包子让吃过的人越来越失望了,先不说价格比普通包子高出多少,包子的味道就比之前逊色了不少,很多天津本地的人也觉得现在的狗不理包子已经远远不如当年那个味道好吃了,而且现在狗不理包子在天津已经得不到人们的青睐了,只是在外地的名气比较响亮一些而已。

该日志标签: 历史, 视频, 文化, 世界, 北京, 故事, 价格, 微博, , , 中国, 时候, 包子, 狗不理, 老字号, 小吃, 天津

乍看是不幸,实际上是幸事

该日志由 samool 发表于 2020-07-25 21:07:54

人生悟语:苦难是一只驶向成功的船,当风暴来临时,别害怕,扬起帆,直面那滔天人海浪、搏击那汹涌的激流吧。

人生不如意事十之八九。生活本是一种承受,人若学会正确对待不幸,那么你所遭受的也许正是你的福气,稻盛和夫曾说过,乍看的不幸,实际是幸事。

看过著名油画大师凡高故居的人都知道,那里有的只是张裂开的木床和破皮鞋。凡高一生潦倒困苦,没有娶妻,但也许是生活的困窘,帮他完成了在艺术上的壮举,使他成为大师中的大师,使他的作品成为经典中的经典。

就人生而言,不幸是个不请自来的不速之客。不幸是根弹簧,我们若向它屈服了,它反而使我们落魄潦倒,甚至在绝望和恐惧中逼迫我们一步步靠近灭亡;如果我们不臣服于它,反而会变得更坚强更勇敢。

世界上没有完美无缺的东西,不幸便是人生完璧中的瑕疵。其实不完美才是一种美,在不断的争取中,不断地承受失败与挫折时,才能发现快乐。稻盛和夫青年时代,曾经在没有选择的情况下进入了当时一个很不景气的公司上班,拖欠工资是家常便饭,他也曾为此失落过,然而,就在那样一种环境下,稻盛倾注心血在实验研究上,取得了一个又一个可喜的成果。他对工作的态度也有了180度的大转弯,从厌恶到喜爱,这为他日后的成功打下了基础。

风雨对于温室里的花朵而言绝对是灭顶之灾,不幸对于幸运儿而言无疑是致命的打击,毫无力量去抗拒迎击。因为幸运儿习惯了没有挫折和不幸的苦涩人生,在他们的生活中只有一帆风顺、心想事成,他们的字典里没有别有深味的“不幸”二字,而那些经常遭受不幸的人来说,他们的意志品质都是非常坚强的。他们深刻地明白,风调雨顺、风和日丽只是偶然光临,暴风骤雨、电闪雷鸣才是人生的常客。

著名心理学家威廉汤姆斯说过,我们所谓的不幸和苦难,很大的程序上,要归结于个人对现象所持的看法。更重要的则是,一个人以什么样的心情与态度来面对和处理这些难题,最后的结果是迥然不同的。因此,我们不难发觉,即使是出于同样的环境和状态,有人认为是不幸和苦难,有人却认为这是千载难逢的良机与顺境。

成功的人为什么能成功?因为对他们来说,每一个因素都是成功的良机,甚至包括不幸,不管身处何处,他们都会以积极、自信与乐观的态度去努力、去积淀自己,他们是奇迹的创造者。与此相反,另一些人持有消极与失败的心态,不愿意承担不幸,这样的人注定一辈子要潦倒。不同的心态,做出的不同的反应致使事情的结果截然相反。因此遇到任何挫折或打击时,千万不要呼天抢地,要微笑着告诉自己那是造化的考验。

高尔基曾把苦难比作大学,几乎所有的成功人士都是从不幸中毕业的,不幸教给你坚强勇敢,更教会你拼博向上,这也是正如稻盛和夫指出的那样,苦难是一只驶向成功的船,当风暴来临时,别害怕,扬起帆,直面那滔天的海浪,博击那汹涌的激流吧。

该日志标签: 工作, 心情, 人生, 生活, 经典, 世界, 程序, 环境, 上班, 公司, 稻盛和夫, 失败, , 作品, 工资, 不幸, 苦难, 潦倒, 幸运儿

过来人劝你35岁之后不要轻易去卖保险(二)

该日志由 samool 发表于 2020-07-19 16:34:00

过来人劝你35岁之后不要轻易去卖保险
虽然你身边的朋友都会嘲讽你
某某去卖保险
“卖保险”会成为一个讽刺的词语
除非你心里特别强大
不然身边的朋友冷嘲热讽会让你压力山大

卖保险其实就是卖一种观念,卖的一份合同,几张纸
卖保险是世界上最难的销售
健康的时候不需要保险
等需要保险的时候,却买不到
这个世界有两样产品
一种是趋利的产品,比如手机,买来之后就可以使用,看到他的好处
另一种是避害的产品,如安全带,平时基本上没什么用,但在关键时刻可以起到意想不到作用

要做好这个工作
需要你不断地学习,要学保险基础知识
打了好基础之后,医学、法律相关的知识也要储备
最最重要的是
还要学习心理学,懂人情世故、练口才、还要察言观色
每一个客户都是单独的个体
思想观点、关注点都不一样
签单并非你想的那么容易

前三个月都能签单
因为最初的客户都是你最熟悉人
最信任的人
所以前期签单还是比较容易
第一圈熟人做完
当做二、三、四圈层的时候
你会发现难度会逐渐提升

保险有两条路可以走
一是签单多,业绩好
另一条路增员(招募人员,组建自己的团队)
招人比签单更难
如果节奏没有掌握好
绝大多数人干不过半年
因为干保险是没有底薪的
有业绩才有工资,没业绩=工资为0
所以大部分人,在半年后就离开了
在保险行业,离开的人叫“脱落”
卖保险和做生意差不多
也叫无成本创业,内部叫做保险企业家
虽说是无成本,要做好这份工作
其实你要付出很多努力
要忍受常人所不能忍

卖保险是自由的
上午大多在公司学习、开会
下午是自由活动时候
早上打卡,下班不用打卡
也正因为这种自由
没有完全的自律,肯定也坚持不了多久
半年之内不开单,工资为0,绝大多数人都会离开
重新找一份有底薪的工作

看似进入门槛很低
是个人就可以卖保险
现实却是残酷的
保险公司女性居多的原因
是因为女性相对来说
压力比男性小很多
当做兼职也不错
对于一个男人来说
如果你没有十足的准备
我建议你不要进入保险行业

如果没有存款
我建议不要进入保险行业
如果没有被动收入
我建议不要进入保险行业
如果没有人脉,不要进入
如果沟通能力差,不要进入
如果自律能力差,不要进入

(待续)
下一次,给大家分享一下保险公司的套路,敬请期待

该日志标签: 活动, 朋友, 工作, 女性, 世界, 手机, 男人, 收入, 合同, 压力, 团队, 创业, 思想, 公司, 销售, 保险, 客户, 过来人, 不要, 进入, 工资, 自律

世界10大“名”车 图文并茂版!

该日志由 samool 发表于 2007-09-21 12:53:53

名车估计大家也看不少了,其华丽的外表、丰富的内涵实在让车迷们津津乐道不已。不过今天,来带大家来看看另类的十大“名”车!到底他们长得什么样:

● 车型:丰田霸道 拉风指数:★★★★★
车况:马路专用清洁车,超强霸道功能, 自动无水多扫帚清扫系统500米自动防靠近预警系统。 
a.jpg

● 车型:林肯-加长型 沙漠淡黄色,特别加长型。 拉风指数:★★★★
车况:豪华真皮外饰, 一匹骆驼力,敞蓬,手牵自动档,ABS超强沙漠越野性能, 驾驶员自动跟随系统。 
b.jpg


● 车型:大众 大众化警务专用车。 拉风指数:★★★★
车况:简洁实用内外饰,手动快慢档 扯开嗓子自动警报系统,后座防偷窥及逃跑系统 具备良好的胡同、乡间跟踪及越野性能。
c.jpg


● 车型:保时捷 拉风指数:★★★★
车况:浪漫天蓝色,简洁实用外饰,一匹人力,敞蓬, 脚控快慢档较强的走街串巷越野性能,极具亲和力。
d.jpg 

● 车型:宝马 拉风指数:★★★★
车况:华贵乳白色,真皮豪华外饰,一匹马力,敞蓬, 声控自动挡,ABS防盗自动发声报警或逃跑系统, 自动定速巡航系统。
e.jpg 

● 车型:奥迪 拉风指数:★★★
车况:不用多说了!自己看吧! 够奥迪了吧。
f.jpg

● 车型:奔驰 拉风指数:★★★
车况: 经典古铜色,真木豪华内外饰,1~3匹马力。
g.jpg

● 车型:丰田 拉风指数:★★★
车况:自然浅灰色,豪华真牛皮外饰。
h.jpg

● 车型:悍马 拉风指数:★★★★★
车况:经典显眼红色,1~3匹人力,敞蓬,全自动脚控多档 超强全天候全方位越野性能,随时随地乱草丛中隐蔽功能, 卫星难以定位系统。
i.jpg

● 车型:蓝鸟 拉风指数:★★★
车况:亮丽花鸟色,豪华真羽毛外饰,一匹鸟力,敞蓬, 声控自动档,ABS驾驶员自动跟随系统,超大真铁轻型豪华轮胎。
j.jpg

该日志标签: 世界, 汽车, 图片