Linux-Android启动之zImage生成过程详解

可以看到,在顶层makefile的第278行,包含了scripts/Kbuild.include文件,在这里定义了大量的函数和变量,供顶层makefile和其他makefile文件使用。
 
在顶层makefile文件的第412行,包含了arch/arm/Makefile。这个是体系结构相关makefile文件。它定义了体系结构相关的一些变量及规则。
 
当执行”make”时,arch/arm/Makefile中的185行的规则将是make遇到的第一个规则:
 
all:   $(KBUILD_IMAGE)
 
KBUILD_IMAGE这个变量是arch/arm/Makefile的第182行定义。
 
KBUILD_IMAGE := zImage
 
然后看zImage的构建规则,在arch/arm/Makefile的第212行开始定义
 
zImage Image xipImage bootpImage uImage: vmlinux
       $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
 
build变量在scripts/Kbuild.include文件中第114行定义:
 
build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
 
boot变量在arch/arm/Makefile的187行定义:
 
boot := arch/arm/boot
 
MACHINE变量的值在arch/arm/Makefile的147行开始定义
 
ifneq ($(machine-y),)
MACHINE  := arch/arm/mach-$(machine-y)/
else
MACHINE  :=
endif
 
这里machine-y := s3c2410,所以变量MACHINE的值为
 
MACHINE  := arch/arm/mach-s3c2410
 
所以上面的规则可写为如下形势
 
 
zImage: vmlinux
       $(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj= /
       arch/arm/boot MACHINE= arch/arm/mach-s3c2410 arch/arm/boot/ zImage
 
这个规则的依赖是vmlinux,下面先看看这个依赖目标的创建规则。
 
vmlinux目标的规则在顶层Makefile的第738行定义。
 
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
ifdef CONFIG_HEADERS_CHECK
       $(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
       $(call if_changed_rule,vmlinux__)
       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
       $(Q)rm -f .old_version
 
这里涉及到几个变量,先看看这几个变量的定义,前三个变量分别在605、602、603行定义。
 
vmlinux-init := $(head-y) $(init-y)
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
vmlinux-lds  := arch/$(ARCH)/kernel/vmlinux.lds
 
其中head-y在arch/arm/Makefile中第89行定义,
 
head-y            := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
 
init-y在顶层makefile的433行定义
 
init-y              := init/
 
后又在第567行进行处理
 
init-y              := $(patsubst %/, %/built-in.o, $(init-y))
 
所以变量init-y应为
 
init-y              := init/built-in.o
 
因此
 
vmlinux-init := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o init/built-in.o
 
同理,其他几个变量也可通过类似方法进行分析,这里不一一分析了。vmlinux-init这个变量的构建规则在748行定义:
 
$(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
 
这里是一个空命令的规则。空命令行可以防止make在执行时试图为重建这个目标去查找隐含命令。其依赖为vmlinux-dirs,这个变量在顶层Makefile第558行定义:
 
vmlinux-dirs   := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) /
                   $(core-y) $(core-m) $(drivers-y) $(drivers-m) /
                   $(net-y) $(net-m) $(libs-y) $(libs-m)))
 
这个变量指定了一系列要进入的下层目录。他的规则在顶层Makefile第757行定义
 
$(vmlinux-dirs): prepare scripts
       $(Q)$(MAKE) $(build)=$@
 
这里的两个依赖就不分析了,主要看一下这个规则的命令,build和$@变量展开后如下
 
       $(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build  /
        obj =$(vmlinux-dirs)
 
这里会再一次进入scripts/Makefile.build执行83行规则
 
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) /
        $(if $(KBUILD_MODULES),$(obj-m)) /
        $(subdir-ym) $(always)
       @:
 
因为KBUILD_BUILTIN在顶层Makefile中被初始化为1,所以这个规则的依赖有一个builtin-target变量。这个变量在scripts/Makefile.build的78行定义
 
ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif
 
变量obj就是vmlinux-dirs变量指定的目录。所以这里会构建$(vmlinux-dirs)/built-in.o目标,在scripts/Makefile.build文件的261行开始,有这个目标的规则及命令的定义
 
ifdef builtin-target
quiet_cmd_link_o_target = LD      $@
# If the list of objects to link is empty, just create an empty built-in.o
cmd_link_o_target = $(if $(strip $(obj-y)),/
                    $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^),/
                    rm -f $@; $(AR) rcs $@)
 
$(builtin-target): $(obj-y) FORCE
       $(call if_changed,link_o_target),
 
scripts/Makefile.build在第16行开始包含了vmlinux-dirs变量指定目录中的Makefile文件,在这些makefile文件中会指定obj-y变量,它指定的都是一些*.o目标文件,
 
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
 
这些*.o文件的生成方法由scripts/Makefile.build文件202行的模式规则指定
 
%.o: %.c FORCE
       $(call cmd,force_checksrc)
       $(call if_changed_rule,cc_o_c)
 
通过上面这一系列的步骤,就编译链接出由变量vmlinux-init指定的目标,vmlinux-main变量指定的目标的构建与此类似。再看看vmlinux的构建规则
 
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
ifdef CONFIG_HEADERS_CHECK
       $(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
       $(call if_changed_rule,vmlinux__)
       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
       $(Q)rm -f .old_version
 
现在vmlinux的依赖都处理好了,开始执行这个规则的命令,命令
 
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
 
是进行头文件的相关检测,这里不作详细分析。看第二条命令
 
       $(call if_changed_rule,vmlinux__)
 
这里通过函数调用,执行rule_vmlinux__,在顶层Makefile第636行开始定义
 
define rule_vmlinux__
       :
       $(if $(CONFIG_KALLSYMS),,+$(call cmd,vmlinux_version))
 
       $(call cmd,vmlinux__)
       $(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd
 
       $(Q)$(if $($(quiet)cmd_sysmap),                                      /
         echo '  $($(quiet)cmd_sysmap)  System.map' &&)                     /
       $(cmd_sysmap) $@ System.map;                                         /
       if [ $$? -ne 0 ]; then                                               /
              rm -f $@;                                                    /
              /bin/false;                                                  /
       fi;
       $(verify_kallsyms)
endef
 
这里主要还是调用cmd_vmlinux__,定义在顶层Makefile的610行
 
      cmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ /
      -T $(vmlinux-lds) $(vmlinux-init)                          /
      --start-group $(vmlinux-main) --end-group                  /
      $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE ,$^)
 
通过这个命令将变量vmlinux-init和vmlinux-main指定的目标链接成vmlinux文件。链接脚本由vmlinux-lds指定。在顶层 Makefile 605行定义:
 
vmlinux-lds  := arch/$(ARCH)/kernel/vmlinux.lds
 
现在再看一下zImage的构建规则
 
zImage: vmlinux
       $(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj= /
       arch/arm/boot MACHINE= arch/arm/mach-s3c2410 arch/arm/boot/ zImage
 
其依赖vmlinux已经构建完成,它的命令同样是执行scripts/Makefile.build文件,它的开头包含了arch/arm/boot/Makefile文件,在这个文件的第56行开始就是arch/arm/boot/zImage的构建规则:
 
$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
       $(call if_changed,objcopy)
       @echo '  Kernel: $@ is ready'
 
变量obj的值就是arch/arm/boot,前面已经分析过。其依赖  $(obj)/compressed/vmlinux的构建规则在arch/arm/boot/Makefile的53行开始定义的
 
$(obj)/compressed/vmlinux: $(obj)/Image FORCE
       $(Q)$(MAKE) $(build)=$(obj)/compressed $@
 
这个规则的依赖$(obj)/Image的构建规则在arch/arm/boot/Makefile的49行开始定义:
 
$(obj)/Image: vmlinux FORCE
       $(call if_changed, objcopy)
       @echo '  Kernel: $@ is ready'
 
在这个规则中,将前面创建的vmlinux文件通过二进制工具objcopy进行处理,在scripts/Makefile.build的第19行包含了scripts/Makefile.lib
 
include scripts/Makefile.lib
 
在这个makefile文件中,有cmd_objcopy的定义,在156行开始定义
 
quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
 
变量OBJCOPY在顶层Makefile中289行定义:
 
OBJCOPY             = $(CROSS_COMPILE)objcopy
 
OBJCOPYFLAGS变量在arch/arm/Makefile中第15行定义
 
OBJCOPYFLAGS  :=-O binary -R .note -R .comment –S
 
所以命令cmd_objcopy可扩展为
 
cmd_objcopy = $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment –S $< $@
 
这就是处理vmlinux的命令。然后看看规则
 
$(obj)/compressed/vmlinux: $(obj)/Image FORCE
       $(Q)$(MAKE) $(build)=$(obj)/compressed $@
 
的命令行,变量扩展后为:
 
$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj= /
             $(obj)/compressed $(obj)/compressed/vmlinux
 
于是在scripts/Makefile的开头会包含arch/arm/boot/compressed/Makefile文件,并执行其中的$(obj) /vmlinux目标所在的规则,在这个Makefile文件的第98行开始定义:
 
$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o /
             $(addprefix $(obj)/, $(OBJS)) FORCE
       $(call if_changed,ld)
       @:
 
这里先看$(obj)/piggy.o,在arch/arm/boot/compreseed/Makefile的103行开始
 
$(obj)/piggy.gz: $(obj)/../Image FORCE
       $(call if_changed,gzip)
 
$(obj)/piggy.o:  $(obj)/piggy.gz FORCE
 
这两个规则的第一个就是把由vmlinux生成的Image进行压缩生成piggy.gz,然后生成piggy.o
 
cmd_ld命令在scripts/Makefile.lib文件149行定义:
 
quiet_cmd_ld = LD      $@
cmd_ld = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_$(@F)) /
              $(filter-out FORCE,$^) -o $@
 
这里根据链接脚本arch/arm/boot/compressed/vmlinux.lds链接生成了arch/arm/boot/compressed/vmlinux文件。然后在arch/arm/boot/Makefile的第56行的规则中
 
$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
       $(call if_changed,objcopy)
       @echo '  Kernel: $@ is ready'
 
经过objcopy处理后便生成的最终的zImage 。
 
 
 
下面看一下顶层Makefile生成的vmlinux以及arch/arm/boot/compressed/makefile生成的vmlinux的起始地址。
 
通过顶层Makefile中的规则生成vmlinux是根据arch/arm/kernel/vmlinux.lds这个脚本链接生成的。arch/arm/kernel/vmlinux.lds是由arch/arm/kernel/vmlinux.lds.S生成的,其生成规则在scripts/Makefile.build的第246行开始定义
 
quiet_cmd_cpp_lds_S = LDS     $@
      cmd_cpp_lds_S = $(CPP) $(cpp_flags) -D__ASSEMBLY__ -o $@ $<
 
%.lds: %.lds.S FORCE
       $(call if_changed_dep,cpp_lds_S)
 
在arch/arm/kernel/vmlinux.lds.S的开始处有
 
#ifdef CONFIG_XIP_KERNEL
       . = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);
#else
       . = PAGE_OFFSET + TEXT_OFFSET;
#endif
 
我们这里的起始地址就是PAGE_OFFSET + TEXT_OFFSET。
 
在include/asm-arm/memory.h的49行开始有
 
#ifndef PAGE_OFFSET
#define PAGE_OFFSET        UL(0xc0000000)
#endif
 
而arch/arm/kernel/vmlinux.lds.S的开头有
 
#include <asm/memory.h>
 
asm是一个符号,链接到asm-arm上的
 
在arch/arm/Makefile第140行,有
 
TEXT_OFFSET := $(textofs-y)
 
第90行有
 
textofs-y := 0x00008000
 
所以TEXT_OFFSET := 0x00008000
 
在153行有export TEXT_OFFSET将此变量输出。这样arch/arm/kernel/vmlinux.lds.S也就获得了PAGE_OFFSET + TEXT_OFFSET的值。
 
 
现在看看arch/arm/boot/compressed/makeflie生成的vmlinux。它是根据arch/arm/boot/compressed/vmlinux.lds链接脚本生成的。这个脚本由arch/arm/boot/compressed/vmlinux.lds.in生成,在这个文件的开始处有
 
  . = TEXT_START;
 
现在看arch/arm/boot/compressed/Makefile,在110行有
 
$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile .config
       @sed "$(SEDFLAGS)" < $ $@
 
这就是由vmlinux.lds.in生成vmlinux.lds的规则,在它的命令中有个变量SEDFLAGS,在74行定义
 
SEDFLAGS    = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/
 
这里就把TEXT_START换成了ZTEXTADDR。再往上看从66行起
 
ifeq ($(CONFIG_ZBOOT_ROM),y)
ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT)
ZBSSADDR    := $(CONFIG_ZBOOT_ROM_BSS)
else
ZTEXTADDR := 0
ZBSSADDR    := ALIGN(4)
endif
 
如果zImage是从ram中启动ZTEXTADDR      := 0,否则从rom或flash启动时ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT),这里要在配置时设定CONFIG_ZBOOT_ROM_TEXT的值。
 
到这里,关于zImage的生成过程算是可以结束了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/243142.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

行业发展的大势所趋 嵌入式机器视觉系统前景一片大好

机器视觉系统是一种非接触式的光学传感系统。它同时集成软硬件&#xff0c;能够自动地从所采集到的图像中获取信息或者产生控制动作。自起步发展到现在&#xff0c;主要经历了数字电路组成、PC机和输出设备组成、嵌入式三个阶段。 其中&#xff0c;嵌入式机器视觉系统依托专业计…

优先编码器

优先编码器 题目描述 8-3优先编码器的功能表 timescale 1ns/1nsmodule encoder_83(input [7:0] I ,input EI ,output wire [2:0] Y ,output wire GS ,output wire EO );reg [2:0]Y_reg;reg GS_reg;reg EO…

OVS vxlan 底层结构分析 - 每天5分钟玩转 OpenStack(148)

上一节创建了 vxlan100_net 并部署 instance&#xff0c;今天我们来分析底层网络结构。 控制节点 执行 ovs-vsctl show&#xff1a; br-int br-int 连接了如下 port: tap0d4cb13a-7a 是 vxlan100_net 的 DHCP 服务对应的 interface。 qvoa2ac3b9a-24 将 cirros-vm1 虚拟网卡连…

Linux-Android启动之Init进程前传

对Linux-Android系统的启动做了一些分析&#xff0c;下面的一篇文章侧重讲述Linux启动过程中函数Start_kernel()被调用之前的一些分析&#xff0c;同时也对函数Start_kernel()之后的代码流程作了概述&#xff0c;我希望关于Linux-Android系统的启动的专题能够继续地写下去&…

如何正确入门Windows系统下驱动开发领域?

[作者]猪头三作者网站: http://www.x86asm.com原文链接: http://blog.csdn.net/Code_GodFather/...0/5975901.aspx[贡献者]1> defddr 看雪学院2> StudyRush 看雪学院[序言]很多人都对驱动开发有兴趣,但往往找不到正确的学习方式.当然这跟驱动开发的本土化资料少有关系.大…

OVS VxLAN Flow 分析 - 每天5分钟玩转 OpenStack(149)

OVS 的数据流向都是由 Flow 规则控制的&#xff0c;今天我们就来分析 VxLAN 的 Flow 规则。 提个醒&#xff1a;这可能是本教程最烧脑的一节&#xff0c;lets rock it ! 下面分析控制节点上的 flow rule&#xff0c;计算节点类似。 br-int 的 flow rule br-int 的 rule 看上去虽…

制作 OpenStack Linux 镜像 - 每天5分钟玩转 OpenStack(151)

这是 OpenStack 实施经验分享系列的第 1 篇。 OpenStack 的 instance 是通过 Glance 镜像部署的&#xff0c;所以准备镜像是必须要做的工作。本节介绍 Linux 镜像的制作方法&#xff0c;后面还会讨论 Windows 镜像。 下载clould 镜像 最简单的方法是使用标准镜像。主流的Linux发…

NDIS与WinSock关系之自我扫盲

起来真是雷人&#xff0c;最近几天纠结与一个最基本的概念&#xff0c;就是NDIS与WinSock关系&#xff0c;想来想去都没有想明白&#xff0c;真实汗Ing&#xff0c;赶紧找了篇精美的文章来扫盲一下。 原文如下&#xff1a; 文章转自http://www.cnblogs.com/sankye/articles/16…

WDF驱动中KMDF与UMDF区别

众所周知&#xff0c; 早期的Windows 95/98的设备驱动是VxD(Virtual Device Driver)&#xff0c;其中x表示某一类设备。从Windows 2000开始&#xff0c;开发驱动程序必以WDM&#xff08;Windows Driver Model&#xff09;为基础的&#xff0c;但是&#xff0c;如果使用DDK来开发…

根据状态转移表实现时序电路

根据状态转移表实现时序电路 某同步时序电路转换表如下&#xff0c;请使用D触发器和必要的逻辑门实现此同步时序电路 电路的接口如下图所示 A表示输入&#xff0c;Y 表示输出 理解状态转移表&#xff0c;画成状态转移图 timescale 1ns/1nsmodule seq_circuit(input …

Facebook、LinkedIn、Airbnb、Google专家聚首QCon,他们会带来什么?

4月16日~18日&#xff0c;QCon北京2017将在北京国家会议中心举行。现已确认来自海外的Google、Facebook、Airbnb、LinkedIn、Confluent、AppDynamics等公司&#xff0c;国内的百度、阿里巴巴、腾讯、京东、滴滴出行、奇虎360、爱奇艺、微博、bilibili等公司的100余位技术专家担…

Devoxx 2017美国大会首日重要演讲一览

Devoxx美国大会今天开幕。\u0026#xD;\n\u0026#xD;\nDevoxx是北美版的欧洲软件大会&#xff08;European Software Conference&#xff09;。广受追捧的欧洲软件大会由Stephan Janssen在2001年创立&#xff0c;组织方是比利时Java用户组&#xff08;BeJUG&#xff0c;Belgian Ja…

Linux-Android启动之Machine-Init函数

Linux/Android启动之Machine-Init函数 前言&#xff1a; 前面写过两篇Linux/Android的启动过程分析&#xff0c;这篇接着前两篇的知识点进行分析。 Linux/Android的启动过程包括了很多内容&#xff0c;其中有些需要了解&#xff0c;有些则需要在系统移植的时候进行修改。本篇文…

cache 是什么意思 它包括的L1,L2,L3分别是什么东西?

CPU缓存缓存大小也是CPU的重要指标之一&#xff0c;而且缓存的结构和大小对CPU速度的影响非常大&#xff0c;CPU内缓存的运行频率极高&#xff0c;一般是和处理器同频运作&#xff0c;工作效率远远大于系统内存和硬盘。实际工作时&#xff0c;CPU往往需要重复读取同样的数据块&…

边沿检测—以脉冲形式给出信号

边沿检测—以脉冲形式给出信号 题目描述&#xff1a; 有一个缓慢变化的1bit信号a&#xff0c;编写一个程序检测a信号的上升沿给出指示信号rise&#xff0c;当a信号出现下降沿时给出指示信号down。 注&#xff1a;rise,down应为单脉冲信号&#xff0c;在相应边沿出现时的下一个…

贷款秒拒?你可能进了“灰名单”!

灰名单/GRAY LIST今天有客户向我反映&#xff0c;他的征信良好没有半点问题&#xff0c;只有一张信用卡备用&#xff0c;没有一次逾期&#xff0c;但是最近想申请贷款都是被秒拒。他觉得很郁闷&#xff0c;是不是办了假的贷款&#xff1f;他完全不知道被拒的理由&#xff0c;只…

Linux--根文件系统的挂载过程分析

前言&#xff1a; 本篇文章以S3C6410公版的Linux BSP和U-Boot来进行分析&#xff0c;文中所有提及的名词和数据都是以该环境为例&#xff0c;所有的代码流程也是以该环境为例来进行分析。哈哈。如果有不正确或者不完善的地方&#xff0c;欢迎前来拍砖留言或者发邮件到guopeixi…

Troubleshooting OpenStack Bug- 每天5分钟玩转 OpenStack(162)

这是 OpenStack 实施经验分享系列的第 12 篇。 问题描述 客户报告了一个问题&#xff1a;对 instance 执行 migrate 操作&#xff0c;几个小时了一直无法完成&#xff0c;不太正常。 问题分析 遇到这种情况&#xff0c;第一个要检查的就是 instance 所在计算节点的 nova-comput…

ROM简单实现

ROM简单实现 题目描述 实现一个深度为8&#xff0c;位宽为4bit的ROM&#xff0c;数据初始化为0&#xff0c;2&#xff0c;4&#xff0c;6&#xff0c;8&#xff0c;10&#xff0c;12&#xff0c;14。可以通过输入地址addr&#xff0c;输出相应的数据data 接口信号图如下&…

Fedora gedit 打开txt文件乱码的解决

编码格式不同&#xff0c;fedora打开 windows下的文本文件经常出现乱码。解决办法终端输入命令&#xff1a;$ gsettings set org.gnome.gedit.preferences.encodings auto-detected "[UTF-8, GB18030, GB2312, GBK, BIG5, CURRENT, UTF-16]"$ gsettings set org.gn…