Cargo создает пустой файл ELF

Я пытаюсь использовать этот ответ, написав собственную цель .json файл с "linker-flavor":"gcc", Моя полная цель .json файл:

{
  "llvm-target": "avr-atmel-none",
  "cpu": "atmega328p",
  "target-endian": "little",
  "target-pointer-width": "16",
  "os": "none",
  "target-env": "gnu",
  "target-vendor": "unknown",
  "arch": "avr",
  "data-layout": "e-p:16:16:16-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-n8",

  "executables": true,

  "linker": "avr-gcc",
  "linker-flavor": "gcc",
  "pre-link-args": {
    "gcc": ["-Os -mmcu=atmega328p"]
  },
  "exe-suffix": ".elf",
  "post-link-args": {
    "gcc": ["-Wl,--gc-sections"]
  },

  "no-default-libraries": false
}

Бег cargo build с этим заканчивается без каких-либо сообщений об ошибках:

$ cargo build --release -v
   Compiling core v0.1.0 (https://github.com/gergoerdi/rust-avr-libcore-mini?rev=adda44aa91ac517aab6915447592ee4cad26564c#adda44aa)
     Running `rustc --crate-name core /home/cactus/.cargo/git/checkouts/rust-avr-libcore-mini-37e279d93a70b45a/adda44a/src/lib.rs --crate-type lib --emit=dep-info,link -C opt-level=3 -C metadata=655bb622dd229da9 -C extra-filename=-655bb622dd229da9 --out-dir /home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps --target avr-atmega328p -L dependency=/home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps -L dependency=/home/cactus/prog/rust/avr/chip8-avr/target/release/deps --cap-lints allow`
   Compiling chip8-engine v0.1.0 (https://github.com/gergoerdi/rust-avr-chip8-engine?rev=c6f88737bae4dae0bd6c5c2bbc73737e6dfadfcd#c6f88737)
     Running `rustc --crate-name chip8_engine /home/cactus/.cargo/git/checkouts/rust-avr-chip8-engine-4bce60f3f178d33a/c6f8873/src/lib.rs --crate-type lib --emit=dep-info,link -C opt-level=3 -C metadata=2197ff1f15f697c9 -C extra-filename=-2197ff1f15f697c9 --out-dir /home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps --target avr-atmega328p -L dependency=/home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps -L dependency=/home/cactus/prog/rust/avr/chip8-avr/target/release/deps --extern core=/home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps/libcore-655bb622dd229da9.rlib --cap-lints allow`
   Compiling chip8-avr v0.1.0 (file:///home/cactus/prog/rust/avr/chip8-avr)
     Running `rustc --crate-name chip8_avr src/main.rs --crate-type bin --emit=dep-info,link -C opt-level=3 -C metadata=014a8fed19cbc611 -C extra-filename=-014a8fed19cbc611 --out-dir /home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps --target avr-atmega328p -L dependency=/home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps -L dependency=/home/cactus/prog/rust/avr/chip8-avr/target/release/deps --extern chip8_engine=/home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps/libchip8_engine-2197ff1f15f697c9.rlib --extern core=/home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps/libcore-655bb622dd229da9.rlib`
    Finished release [optimized] target(s) in 15.99 secs

Тем не менее, полученный файл ELF .text раздел пуст:

$ avr-objdump -h target/avr-atmega328p/release/chip8-avr.elf 

target/avr-atmega328p/release/chip8-avr.elf:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000000  00000000  00000000  00000074  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00800060  00000000  00000074  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .stab         0000012c  00000000  00000000  00000074  2**2
                  CONTENTS, READONLY, DEBUGGING
  3 .stabstr      0000005d  00000000  00000000  000001a0  2**0
                  CONTENTS, READONLY, DEBUGGING
  4 .comment      00000011  00000000  00000000  000001fd  2**0
                  CONTENTS, READONLY

Так что, чтобы выяснить, что происходит, я решил заменить avr-gccс небольшим шеллскриптом, который записывает свои аргументы, прежде чем передать его реальному avr-gcc исполняемый файл.

Это показывает мне, что rustc/cargo пытается запустить следующую командную строку, чтобы сделать связывание:

/usr/bin/avr-gcc -Os -mmcu=atmega328p \
  -L /home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/avr-atmega328p/lib \
  /home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps/chip8_avr-014a8fed19cbc611.0.o \
  -o /home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps/chip8_avr-014a8fed19cbc611.elf \
  -Wl,--gc-sections \
  -L /home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps -L /home/cactus/prog/rust/avr/chip8-avr/target/release/deps -L /home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/avr-atmega328p/lib \
  -Wl,-Bstatic /home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps/libchip8_engine-2197ff1f15f697c9.rlib \
  /home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps/libcore-655bb622dd229da9.rlib \
  -Wl,-Bdynamic -Wl,--gc-sections

Если я запускаю ту же самую команду вручную с теми же переменными окружения, я получаю хороший файл ELF с правильным содержимым (обратите внимание, что его .text раздел не пустой)

$ /usr/bin/avr-gcc -Os -mmcu=atmega328p -L /home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/avr-atmega328p/lib /home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps/chip8_avr-014a8fed19cbc611.0.o -o /home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps/chip8_avr-014a8fed19cbc611.elf -Wl,--gc-sections -L /home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps -L /home/cactus/prog/rust/avr/chip8-avr/target/release/deps -L /home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/avr-atmega328p/lib -Wl,-Bstatic /home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps/libchip8_engine-2197ff1f15f697c9.rlib /home/cactus/prog/rust/avr/chip8-avr/target/avr-atmega328p/release/deps/libcore-655bb622dd229da9.rlib -Wl,-Bdynamic -Wl,--gc-sections
$ avr-objdump -h target/avr-atmega328p/release/deps/chip8_avr-014a8fed19cbc611.elf  
target/avr-atmega328p/release/deps/chip8_avr-014a8fed19cbc611.elf:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         0000020e  00800100  00001a56  00001af0  2**4
                  CONTENTS, ALLOC, LOAD, DATA
  1 .text         00001a56  00000000  00000000  00000094  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .bss          000001fa  0080030e  0080030e  00001cfe  2**0
                  ALLOC
  3 .stab         000007ec  00000000  00000000  00001d00  2**2
                  CONTENTS, READONLY, DEBUGGING
  4 .stabstr      000000b0  00000000  00000000  000024ec  2**0
                  CONTENTS, READONLY, DEBUGGING
  5 .comment      00000011  00000000  00000000  0000259c  2**0
                  CONTENTS, READONLY

Так почему же cargo беззвучно создает бессмысленный пустой файл ELF, если выполнение (предположительно) той же команды из оболочки приводит к действительному файлу ELF?

1 ответ

Решение

Это вызвано ошибкой в ​​цели .json файл; в частности, эта часть:

"pre-link-args": {
  "gcc": ["-Os -mmcu=atmega328p"]
},

Аргументы передаются напрямую как argv для компоновщика, поэтому несколько аргументов должны быть разделены на несколько элементов массива здесь:

"pre-link-args": {
  "gcc": ["-Os", "-mmcu=atmega328p"]
},

Причина, по которой эта проблема не обнаруживается при использовании специальной версии журнала avr-gcc является то, что журнал содержит только все аргументы вместе, поэтому не было никакой разницы между двумя представлениями.

Что касается avr-gcc '-Os -mmcu=atmega328p' создавая пустой .elf файл, кажется, что это просто побочный эффект не указав (действительный) -mmcu аргумент.

Другие вопросы по тегам