加载警告:找不到入口符号_start
load warning: cannot find entry symbol _start
我正在学习汇编编程。下面是打印 'Hello, World!' 的简单程序。虽然程序运行完美,但我在 loading
时收到警告消息
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048080
这是代码:
section .data
msg db 'Hello, world!', 0xa
len equ $ - msg
section .text
global main
main:
mov ebx, 1
mov ecx, msg
mov edx, len
mov eax, 4
int 0x80
mov eax, 1
int 0x80
谁能解释一下这个警告的意思。我正在使用 nasm
和 ubuntu 14
。
使用标签 _start
而不是 main
作为 ELF 入口点。 main
暗示它就像 C main
函数,但这甚至不是函数(例如 you can't ret
)。
你没有说,但从错误消息和代码我假设你正在使用 nasm -felf32 hello32.asm && ld -melf_i386 -o hello32 hello32.o
构建你的 32 位代码
(如果您实际上正在构建 64 位代码,那么您很幸运它恰好可以工作,但是一旦您使用 esp
而不是 rsp
进行任何操作,它就会崩溃。 )
错误消息来自 ld
,而不是来自 nasm
。它在消息中说的很对。 Tim 的评论是正确的:ld
在它 link 的文件中查找 _start
符号,但如果找不到,则将入口点设置为文本段的开头。
您定义的其他 global/external 符号并不重要。 main
在这里完全没有关系,可以指向任何你想要的地方。它只对反汇编输出和类似的东西有用。如果您删除 global main
/ main:
行,或将它们更改为任何其他名称,您的代码将完全相同。
将其标记为 main
是不明智的,因为 ELF 入口点不是函数。它是 not main()
,并且不接收 argc
和 argv
参数,并且不能 ret
因为 ESP 指向argc
而不是 return 地址。
如果您 link 使用 gcc / glibc 的 CRT 启动代码查找 main
符号并在初始化 libc 后调用它,则仅使用 main
。 (所以像 printf 这样的函数可以工作。技术上动态的 linker 钩子让 libc 在你的 _start
之前初始化自己,如果你 linked 它,但通常不要这样做,除非你确切地理解你的正在做)。相关:Assembling 32-bit binaries on a 64-bit system (GNU toolchain)
例如gcc -m32 -no-pie -o hello main.o
如果你定义一个 main:
而不是 gcc -m32 -static -nostdlib -o hello start.o
(相当于你的 ld
)。
(在过去的几年里,Linux 发行版有 configured GCC with -pie
as the default,它需要 position-independent 代码。但是在没有 RIP-relative 寻址的 32 位模式下,这真的很不方便(例如,查看 GCC asm 输出),这意味着 ld
不会为您将 call printf
转换为 call printf@plt
。因此对于遵循大多数教程的大多数 hand-written asm,您需要传统的 non-PIE 可执行文件,因此不需要文本重定位。)
我建议您 link 使用 gcc
而不是 ld
.
您的目标文件(无论它们是如何生成的)
gcc
将使用适当的选项调用 ld
,因为它对源代码了解更多,并且将为 ld
所做的假设创建任何必要的东西。
你可以尝试用nasm[=15=编译汇编源文件,生成*.o文件,然后使用ld link带参数的*.o文件-e main.表示指定main为程序入口
您应该使用 _start 来指示 nasm 汇编程序应该从哪里开始执行,而不是 main。
敌人例如:
section .text
global _start
_start:
mov ebx, 1
mov ecx, msg
mov edx, len
mov eax, 4
int 0x80
mov eax, 1
int 0x80
你的程序有问题,比如
一些语法错误,例如您不能将寄存器值分配给常量,因为常量不能保存任何值,为了存储常量值,我们使用变量
在组装你的程序时我遇到下面提到的组装时间错误
没有这样的指令:msg db 72ello,world!440xa'
assign.S:3: Error: no such instruction:
len equ $ - msg'
assign.S:4: 错误: 没有这样的指令: section .text'
assign.S:5: Error: no such instruction:
global main'
assign.S:7: 错误:mov'
assign.S:8: Error: too many memory references for
mov' 的内存引用过多
assign.S:9: 错误:mov'
assign.S:10: Error: too many memory references for
mov 的内存引用过多'
assign.S:11: 错误:int'
assign.S:12: Error: too many memory references for
mov' 的操作数大小不匹配
assign.S:13: 错误:'int' 的操作数大小不匹配
这是在使用 32 位英特尔处理器的 gnu 编译器上为您提供相同输出的代码
.section .rodata
消息:
.string "Hello World"
.section .text
.globl main
.type main,@function
main:
pushl $msgp
call printf
addl ,%esp
pushl [=10=]
call exit
用最近取的名字保存此代码Hello.S
与
$ as -o Hello.o Hello.S
link 与
$ ld -o Hello.o -lc -dynamic-linker /lib.ld.linux.so.2 -e main -Hello.o
至 运行
$ ./你好
希望对您有所帮助
要编译和执行您的程序,您可以创建 bash
脚本如下:
compile64.sh
!/bin//bash
echo "Assembling with Nasm"
nasm -f elf64 -o .o .asm
echo "Linking ... "
gcc -o .o
echo "Done !"
$ ./compile64 nameOftheFile (without extension)
我不知道这是否是一个有效的修复,但似乎对我有用:
尝试使用选项
--entry main
链接您的内核 C 代码时。
ld -o kernel.bin -Ttext 0x1000 kernel_entry.o kernel.o --oformat binary --entry main
我正在学习汇编编程。下面是打印 'Hello, World!' 的简单程序。虽然程序运行完美,但我在 loading
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048080
这是代码:
section .data
msg db 'Hello, world!', 0xa
len equ $ - msg
section .text
global main
main:
mov ebx, 1
mov ecx, msg
mov edx, len
mov eax, 4
int 0x80
mov eax, 1
int 0x80
谁能解释一下这个警告的意思。我正在使用 nasm
和 ubuntu 14
。
使用标签 _start
而不是 main
作为 ELF 入口点。 main
暗示它就像 C main
函数,但这甚至不是函数(例如 you can't ret
)。
你没有说,但从错误消息和代码我假设你正在使用 nasm -felf32 hello32.asm && ld -melf_i386 -o hello32 hello32.o
(如果您实际上正在构建 64 位代码,那么您很幸运它恰好可以工作,但是一旦您使用 esp
而不是 rsp
进行任何操作,它就会崩溃。 )
错误消息来自 ld
,而不是来自 nasm
。它在消息中说的很对。 Tim 的评论是正确的:ld
在它 link 的文件中查找 _start
符号,但如果找不到,则将入口点设置为文本段的开头。
您定义的其他 global/external 符号并不重要。 main
在这里完全没有关系,可以指向任何你想要的地方。它只对反汇编输出和类似的东西有用。如果您删除 global main
/ main:
行,或将它们更改为任何其他名称,您的代码将完全相同。
将其标记为 main
是不明智的,因为 ELF 入口点不是函数。它是 not main()
,并且不接收 argc
和 argv
参数,并且不能 ret
因为 ESP 指向argc
而不是 return 地址。
如果您 link 使用 gcc / glibc 的 CRT 启动代码查找 main
符号并在初始化 libc 后调用它,则仅使用 main
。 (所以像 printf 这样的函数可以工作。技术上动态的 linker 钩子让 libc 在你的 _start
之前初始化自己,如果你 linked 它,但通常不要这样做,除非你确切地理解你的正在做)。相关:Assembling 32-bit binaries on a 64-bit system (GNU toolchain)
例如gcc -m32 -no-pie -o hello main.o
如果你定义一个 main:
而不是 gcc -m32 -static -nostdlib -o hello start.o
(相当于你的 ld
)。
(在过去的几年里,Linux 发行版有 configured GCC with -pie
as the default,它需要 position-independent 代码。但是在没有 RIP-relative 寻址的 32 位模式下,这真的很不方便(例如,查看 GCC asm 输出),这意味着 ld
不会为您将 call printf
转换为 call printf@plt
。因此对于遵循大多数教程的大多数 hand-written asm,您需要传统的 non-PIE 可执行文件,因此不需要文本重定位。)
我建议您 link 使用 gcc
而不是 ld
.
gcc
将使用适当的选项调用 ld
,因为它对源代码了解更多,并且将为 ld
所做的假设创建任何必要的东西。
你可以尝试用nasm[=15=编译汇编源文件,生成*.o文件,然后使用ld link带参数的*.o文件-e main.表示指定main为程序入口
您应该使用 _start 来指示 nasm 汇编程序应该从哪里开始执行,而不是 main。 敌人例如:
section .text
global _start
_start:
mov ebx, 1
mov ecx, msg
mov edx, len
mov eax, 4
int 0x80
mov eax, 1
int 0x80
你的程序有问题,比如 一些语法错误,例如您不能将寄存器值分配给常量,因为常量不能保存任何值,为了存储常量值,我们使用变量
在组装你的程序时我遇到下面提到的组装时间错误
没有这样的指令:msg db 72ello,world!440xa'
assign.S:3: Error: no such instruction:
len equ $ - msg'
assign.S:4: 错误: 没有这样的指令: section .text'
assign.S:5: Error: no such instruction:
global main'
assign.S:7: 错误:mov'
assign.S:8: Error: too many memory references for
mov' 的内存引用过多
assign.S:9: 错误:mov'
assign.S:10: Error: too many memory references for
mov 的内存引用过多'
assign.S:11: 错误:int'
assign.S:12: Error: too many memory references for
mov' 的操作数大小不匹配
assign.S:13: 错误:'int' 的操作数大小不匹配
这是在使用 32 位英特尔处理器的 gnu 编译器上为您提供相同输出的代码
.section .rodata 消息: .string "Hello World"
.section .text
.globl main
.type main,@function
main:
pushl $msgp
call printf
addl ,%esp
pushl [=10=]
call exit
用最近取的名字保存此代码Hello.S 与 $ as -o Hello.o Hello.S link 与 $ ld -o Hello.o -lc -dynamic-linker /lib.ld.linux.so.2 -e main -Hello.o 至 运行 $ ./你好
希望对您有所帮助
要编译和执行您的程序,您可以创建 bash
脚本如下:
compile64.sh
!/bin//bash
echo "Assembling with Nasm"
nasm -f elf64 -o .o .asm
echo "Linking ... "
gcc -o .o
echo "Done !"
$ ./compile64 nameOftheFile (without extension)
我不知道这是否是一个有效的修复,但似乎对我有用:
尝试使用选项
--entry main
链接您的内核 C 代码时。
ld -o kernel.bin -Ttext 0x1000 kernel_entry.o kernel.o --oformat binary --entry main