这是我的汇编级代码......
section .text
global _start
_start: mov eax, 4
mov ebx, 1
mov ecx, mesg
mov edx, size
int 0x80
exit: mov eax, 1
int 0x80
section .data
mesg db 'KingKong',0xa
size equ $-mesg
Run Code Online (Sandbox Code Playgroud)
输出:
root@bt:~/Arena# nasm -f elf a.asm -o a.o
root@bt:~/Arena# ld -o out a.o
root@bt:~/Arena# ./out
KingKong
Run Code Online (Sandbox Code Playgroud)
我的问题是全球_start用于什么?我和Mr.Google试了一下运气,我发现它用来说明程序的起点.为什么我们不能_start告诉程序在哪里开始,如下面给出的那个在屏幕上产生一种警告
section .text
_start: mov eax, 4
mov ebx, 1
mov ecx, mesg
mov edx, size
int 0x80
exit: mov eax, 1
int 0x80
section .data
mesg db 'KingKong',0xa
size equ $-mesg
root@bt:~/Arena# nasm -f elf a.asm
root@bt:~/Arena# ld -e _start -o out a.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048080
root@bt:~/Arena# ld -o out a.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048080
Run Code Online (Sandbox Code Playgroud)
Sed*_*glu 37
global指令是NASM特定的.它用于将代码中的符号导出到生成的目标代码中的位置.在此处标记_start符号全局,因此其名称将添加到目标代码(a.o)中.linker(ld)可以读取目标代码中的该符号及其值,以便它知道在输出可执行文件中将其标记为入口点的位置.当您运行可执行文件时,它将从_start代码中标记的位置开始.
如果global符号缺少指令,则该符号不会放在目标代码的导出表中,因此链接器无法知道该符号.
如果要使用不同的入口点名称_start(默认值),可以将-e参数指定为ld,如:
ld -e my_entry_point -o out a.o
Run Code Online (Sandbox Code Playgroud)
在声明标签为全局标签之前,该标签不是显式全局的,因此必须使用全局指令。
链接器需要全局标签“ _start”,如果没有全局_start地址,则链接器会抱怨,因为找不到。您没有将_start声明为全局变量,因此它在该代码模块/对象之外不可见,因此对链接程序不可见。
这与C相反,除非您声明它们是局部的,否则隐含事物是全局的
unsigned int hello;
int fun ( int a )
{
return(a+1);
}
Run Code Online (Sandbox Code Playgroud)
问候和乐趣是全局的,在对象外部可见,但这
static unsigned int hello;
static int fun ( int a )
{
return(a+1);
}
Run Code Online (Sandbox Code Playgroud)
使它们在本地不可见。
所有本地:
_start:
hello:
fun:
more_fun:
Run Code Online (Sandbox Code Playgroud)
这些现在对链接器和其他对象全局可用
global _start
_start:
global hello
hello:
...
Run Code Online (Sandbox Code Playgroud)
_start被默认的 Binutils 的ld链接器脚本用作入口点
我们可以使用以下命令查看该链接描述文件的相关部分:
ld -verbose a.o | grep ENTRY
Run Code Online (Sandbox Code Playgroud)
输出:
ENTRY(_start)
Run Code Online (Sandbox Code Playgroud)
在ELF文件格式(我想和其他对象格式),明确地说,项目将开始通过运行的地址e_entry头字段。
ENTRY(_start)告诉链接器在_start从目标文件生成 ELF 文件时将该条目设置为符号的地址。
然后当操作系统开始运行程序(Linux 上的exec系统调用)时,它会解析 ELF 文件,将可执行代码加载到内存中,并将指令指针设置为指定地址。
Sedat-e提到的标志会覆盖默认符号。_start
您还可以使用该-T <script>选项替换整个默认链接器脚本,这是一个设置一些裸机组件的具体示例。
.global 是一个汇编指令,用于在 ELF 文件中将符号标记为全局
ELF 文件包含每个符号的一些元数据,指示其可见性。
观察这一点的最简单方法是使用nm工具。
例如在 Linux x86_64 GAS 独立的 hello world 中:
电源
.text
.global _start
_start:
asm_main_after_prologue:
/* write */
mov $1, %rax /* syscall number */
mov $1, %rdi /* stdout */
lea msg(%rip), %rsi /* buffer */
mov $len, %rdx /* len */
syscall
/* exit */
mov $60, %rax /* syscall number */
mov $0, %rdi /* exit status */
syscall
msg:
.ascii "hello\n"
len = . - msg
Run Code Online (Sandbox Code Playgroud)
编译并运行:
gcc -ffreestanding -static -nostdlib -o main.out main.S
./main.out
Run Code Online (Sandbox Code Playgroud)
nm 给出:
00000000006000ac T __bss_start
00000000006000ac T _edata
00000000006000b0 T _end
0000000000400078 T _start
0000000000400078 t asm_main_after_prologue
0000000000000006 a len
00000000004000a6 t msg
Run Code Online (Sandbox Code Playgroud)
并man nm告诉我们:
如果是小写,符号通常是本地的;如果大写,则符号是全局的(外部的)。
所以我们看到它_global在外部可见(大写T),但msg我们没有标记为.global不是(小写t)。
如果看到多个具有相同名称的全局符号,链接器就会知道如何炸毁,或者更聪明的事情是看到更奇特的符号类型。
如果我们不标记_start为全局,ld就会变得悲伤并说:
找不到入口符号 _start
| 归档时间: |
|
| 查看次数: |
29153 次 |
| 最近记录: |