使用 ld 链接已编译的程序集和 C 文件

Linking a compiled assembly and C file with ld

我编译了这些程序:

  BITS 16
extern _main
start:
      mov ax, 07C0h 
      add ax, 288
      mov ss, ax 
      mov sp, 4096

      mov ax, 07C0h 
      mov ds, ax 

      mov si, text_string 
      call print_string 

      jmp $

      text_string db 'Calling Main Script'
      call _main

print_string:
      mov ah, 0Eh 

.repeat:
      lodsb 
      cmp al, 0
      je .done 
      int 10h
      jmp .repeat 

.done:
      ret 

      times 510-($-$$) db 0
      dw 0xAA55

这是一个测试,只是为了尝试 link他们

int main()
{
  return 0;
}

两者都可以使用以下方法自行编译: gcc -Wall -m32 main.c nasm -f elf bootloader.asm 但是我不能 link 他们使用: ld bootloader.o main.o -lc -I /lib/Id-linux.so.2 我得到这个错误:

ld: i386 architecture of input file `bootloader.o' is incompatible with i386:x86-64 output
ld: i386 architecture of input file `main.o' is incompatible with i386:x86-64 output
ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
ld: bootloader.o: file class ELFCLASS32 incompatible with ELFCLASS64
ld: final link failed: file in wrong format

如有帮助将不胜感激

如果您只是想在 PC 上进行一些简单的汇编编程,实际上不需要 16 位代码,并且不想深入研究引导加载程序和 OS 开发,您可以开始很多通过编写 32 位 (IA32) 或 64 位 (AMD64) 应用程序代码更容易。您可以使用 (Linux) system calls.

而不是 BIOS 中断

i386 的示例 "hello world" 为:

.section .text._start
.global _start
.type  _start, %function

_start:
    mov , %eax
    mov , %ebx
    mov $message, %ecx
    mov , %edx

    int [=10=]x80

    mov , %eax
    xor %ebx, %ebx
    int [=10=]x80

.section .rodata.message
.type message, %object
message:
    .ascii "Hello, World!\n"

Assemble, link 并通过

执行
as --32 test32.S -o test32.o && ld -m elf_i386 test32.o -o test32 && ./test32

AMD64 也一样:

.section .text._start
.global _start
.type  _start, %function

_start:
    mov , %rax
    mov , %rdi
    mov $message, %rsi
    mov , %rdx

    syscall

    mov [=12=]x3c, %rax
    xor %rdi, %rdi
    syscall

.section .rodata.message
.type message, %object
message:
    .ascii "Hello, World!\n"

Assemble, link 并通过

执行
as --64 test64.S -o test64.o && ld -m elf_x86_64 test64.o -o test64 && ./test64

纯属娱乐,ARM(32位)也一样:

.syntax unified
.arch armv6
.arm

.section .text._start
.global _start
.type  _start, %function

_start:
    movs r7, #4
    movs r0, #1
    ldr r1, =#message
    movs r2, #14
    svc #0

    movs r7, #1
    movs r0, #0
    svc #0

    .ltorg

.section .rodata.message
.type message, %object
message:
    .ascii "Hello, World!\n"

Assemble、link 并通过(例如在 Raspberry PI 或 Beaglebone 上执行):

as testarm.S -o testarm.o && ld testarm.o -o testarm && ./testarm

GCC 默认情况下已经动态 linking libc,所以如果你想 linking 手动使用 ld,确保你的 ELF 可执行 [=14] =], 你可以通过 -static 标志。

gcc -o <filename> <filename>.c -static -Wall -m32 然后 link 和 ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o <filename> -lc <filename>.o

我想,因为像 NASM 这样的汇编器有静态的(没有 libc 的独立)你可以直接用 libc 使 ELF 动态可执行,你可以用 -dynamic-linker旗帜。

例如:

x86

nasm -f elf32 -o <filename>.o <filename>.asm
ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o <filename> -lc <filename>.o

x86_64

nasm -f elf64 -o <filename>.o <filename>.asm
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o <filename> -lc <filename>.o