linux 加载警告:找不到条目symbol _start

zc0qhyus  于 2022-11-22  发布在  Linux
关注(0)|答案(7)|浏览(161)

我正在学习汇编编程。下面是一个简单的程序,它打印“Hello,World!”。虽然程序运行得很好,但我在loading
ld:警告:找不到项symbol _start;默认为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

有人能解释一下这个警告的意思吗?我把nasmubuntu 14一起使用。

k5hmc34c

k5hmc34c1#

使用标签_start代替main做为ELF进入点。main表示它类似于C main函式,但这什至不是函式(例如you can't ret)。

你没说,但是从警告消息和代码来看,我假设你正在用nasm -felf32 hello32.asm && ld -melf_i386 -o hello32 hello32.o构建32位代码
(If您实际上是在构建64位代码,幸运的是它恰好可以工作,但只要您使用esp而不是rsp执行任何操作,它就会崩溃。)
警告消息来自ld,而不是来自nasm。消息中有这样的说明。Tim的注解是正确的:ld在它所链接的文件中查找_start符号,但如果没有找到,则将入口点设置为文本段的开头。(这就是为什么这是一个警告,而不是错误。如果您在文件的前面放置了一些其他代码,则执行将在没有global _start/_start:的情况下从那里开始)
不管你定义了什么其他的全局/外部符号。main在这里没有任何相关性,可以指向任何你想要的地方。它只对反汇编输出和类似的东西有用。如果你去掉global main/main:行,或者把它们改成任何其他名称,你的代码会完全一样地工作。

将其标记为main是不明智的,因为ELF入口点 * 不是函数*。它 * 不是 * main(),并且不以标准方式接收argcargv参数,也不能接收ret,因为ESP指向argc而不是返回地址。

只有当您链接gcc / glibc的CRT启动代码时,才使用main,gcc/ glibc的CRT启动代码会查找main符号,并在初始化libc后调用它。(因此printf之类的函数可以工作。从技术上讲,如果您链接了libc,动态链接器钩子会让libc在您的_start之前初始化它自己,但通常不会这样做,除非您完全理解您在做什么)。Assembling 32-bit binaries on a 64-bit system (GNU toolchain)
例如,如果您定义了main:,则为**gcc -m32 -no-pie -o hello main.o**
而不是gcc -m32 -static -nostdlib -o hello start.o
(相当于你的裸ld)。
(For过去几年,Linux发行版提供了configured GCC with -pie as the default,它需要位置无关的代码,但在32位模式下,这确实很不方便,因为在32位模式下,您没有x86-64 RIP相对寻址(例如查看GCC asm输出),并且意味着ld不会为您将call printf转换为call printf@plt。因此对于大多数教程中的大多数手写asm,您需要传统的非PIE可执行文件,因此不需要文本重定位。)

wgxvkvu9

wgxvkvu92#

我建议您将对象文件(无论它们是如何生成的)与gcc链接,而不是与ld链接。
gcc将使用适当的选项调用ld,因为它知道更多关于源代码的信息,并将创建ld所做假设所需的任何内容。

tsm1rwdh

tsm1rwdh3#

我不知道这是否是一个有效的修复,但似乎对我有效:
尝试使用选项

--entry main

同时链接内核C代码。

ld -o kernel.bin -Ttext 0x1000 kernel_entry.o kernel.o --oformat binary --entry main
djp7away

djp7away4#

您可以尝试使用 nasm 编译组件原始程式档,产生 *.o档,然后使用 ld 以参数 *-e main链接 .o档。 这表示main会指定为程式项目。

nbnkbykc

nbnkbykc5#

您应该使用_start而不是main来指示nasm汇编程序应该从何处开始执行。例如:

section .text
global _start
_start:
mov ebx, 1
mov ecx, msg
mov edx, len
mov eax, 4
int 0x80
mov eax, 1
int 0x80
idv4meu8

idv4meu86#

要编译和执行程序,您可以创建bash脚本,如下所示:
compile64.sh

!/bin//bash
echo "Assembling with Nasm"
nasm -f elf64 -o $1.o $1.asm
echo "Linking ... "
gcc -o $1 $1.o
echo "Done !"

$ ./compile64 nameOftheFile  (without extension)
jaxagkaj

jaxagkaj7#

在你的程序中有一些问题,比如一些语法错误,比如你不能把寄存器的值赋给常量,因为常量不能保存任何值,为了存储常量值,我们使用变量
虽然组装你的程序,我得到下面提到的asseble时间错误
无此类说明:msg db 72ello,world!440xa' assign.S:3: Error: no such instruction:透镜设备$ -消息分配。S:4:错误:没有此指令:section .text' assign.S:5: Error: no such instruction:全局主“分配。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编译器上也给予相同的输出。
.段.记录数据消息GP:.string“您好,世界”

.section .text
    .globl  main
    .type   main,@function

main:
    pushl   $msgp
    call    printf
    addl    $4,%esp

    pushl   $0
    call    exit

保存这段代码,最新的名字是Hello.S asseble,用$ as -o Hello.o Hello.S链接,用$ ld -o Hello.o -lc -dynamic-linker/lib.ld.linux.so.2 -e main -Hello.o运行$ ./Hello
我希望这对你有帮助

相关问题