问题
I'm working with an embedded OS like environment, and so size of binaries needs to be as small as possible. I had been using simple flat binary files as an executable, but now I'm trying to use ELF. I'm just using assembly code, but linking with ld. Assembly code:
CPU i386
BITS 32
SECTION .text progbits alloc exec nowrite
GLOBAL start
start:
mov eax, 0
add eax, 1
inc eax
mov eax, 0x12345678
mov dword [0x100000], eax
mov ebx, dword [0x100000]
mov eax, ebx
out 0xF3, al ;dump memory API call
out 0xF0, ax
cli
hlt
Build commands:
yasm -o testbench/test.o testbench/test.asm -f elf32
i386-elf-gcc -T testbench/linker.ld -o test.elf -ffreestanding -nostdlib testbench/test.o -Wl,--gc-sections -dead_strip -fdata-sections -ffunction-sections -Os -nostartfiles -nodefaultlibs
strip --strip-all test.elf
And finally, linker script:
OUTPUT_FORMAT("elf32-i386")
ENTRY(start)
phys = 0x1000;
scratch = 0x100000;
MEMORY
{
coderom (rx) : ORIGIN = phys, LENGTH = 128K
scratchram (!rx) : ORIGIN = scratch, LENGTH = 1024K
}
SECTIONS
{
.text phys : AT(phys) {
code = .;
*(.text.start);
*(.text*)
*(.rodata)
. = ALIGN(4);
} > coderom
__text_end=.;
.data : AT(scratch)
{
data = .;
*(.data)
. = ALIGN(4);
} > scratchram
__data_end=.;
__binary_end = .;
.bss : AT(scratch + (bss - data))
{
bss = .;
*(.bss)
. = ALIGN(4);
} > scratchram
}
Which results in this readelf listing:
earlz@earlz-ubdev:~/x86LibSC$ readelf -a test.elf
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x1000
Start of program headers: 52 (bytes into file)
Start of section headers: 4160 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 1
Size of section headers: 40 (bytes)
Number of section headers: 5
Section header string table index: 4
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00001000 001000 000024 00 AX 0 0 16
[ 2] .data PROGBITS 00100000 001024 000000 00 WA 0 0 1
[ 3] .bss NOBITS 00100000 000000 000000 00 WA 0 0 1
[ 4] .shstrtab STRTAB 00000000 001024 00001c 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x001000 0x00001000 0x00001000 0x00024 0x00024 R E 0x1000
Section to Segment mapping:
Segment Sections...
00 .text
There is no dynamic section in this file.
There are no relocations in this file.
The decoding of unwind sections for machine type Intel 80386 is not currently supported.
No version information found in this file.
As you can see, this should compile to 100 or 200 bytes at the maximum (and did when using flat binary format).. but for some reason this takes up over 4Kb.
How can I reduce the ELF program size as much as possible short of building the ELF file manually in the assembler?
For reference, in this OS environment there are no relocations or dynamic code. It just loads flat program sections.
回答1:
I ended up solving this by using the "-n" (also known as "-nmagic") linker option. This basically tells ld to not worry about aligning program sections on page boundaries. This got me from 4K to about 700 (400 after strip). And then I used sstrip to reduce that further to just about 150 bytes. This is the type of size I was looking to achieve for this use case.
来源:https://stackoverflow.com/questions/47517571/why-does-compiling-this-simple-assembly-code-and-linking-to-elf-result-in-such-a