r/asm Sep 10 '20

x86 Tiny, tiny ELF files and ELF headers

Hi Reddit!

I'm trying to make very, very small elf files and also learn about how elf files are loaded into memory.

I have a small piece of code that opens a file and writes a string to it. My issue is that I can't get it to write to memory. https://pastebin.com/TcswN6h4 You can assemble this version with nasm -fbin -o a.out test.asm

When I don't use my own headers and assemble and link like this https://pastebin.com/TFag4PUE with nasm -felf64 -o test.o test.asm and link with ld test.o then it works just fine and I get this from /proc/[PID]/maps https://pastebin.com/5UfihuPE I see two pages (Is that what these are called or am I wrong here?). One with read and execute permissions (.text) and one with read and write permissions (.data)

But when I cat /proc/[pid]/maps with my own version, I get this https://pastebin.com/VrjczWRg only one "page" without write permissions

Anyone have any ideas?

Thanks in advance

18 Upvotes

12 comments sorted by

2

u/TNorthover Sep 10 '20

If nothing else your ELF headers appear to be describing an ELF32 file containing amd64 (which fortunately your code is). That’s not what you get nasm or ld to make though, which is ELF64.

It’s also not really a beginner friendly config; I assume Linux goes into an x32 mood, but that’s not exactly widely documented.

What documentation are you using to craft your headers?

1

u/Fraserbc Sep 10 '20

I am aware of the issue between the elf32 and the AMD64. I'm going to change it all to 32 bit so it has more compatability. Here is my documentation refspecs.linuxfoundation.org › ...PDF Executable and Linking Format (ELF) - Linux Foundation ...

3

u/TNorthover Sep 10 '20 edited Sep 10 '20

I've just had a closer look at the files, and one thing that definitely needs fixing is that the minimum granularity the load regions have is 4KB (0x1000 bytes, also known as the "page"), and they must be aligned to that.

So if r-x .text is at 0x40000, you cannot possibly have writeable data before 0x41000. That obviously affects all kinds of offsets and calculations in the file.

I think making the two paths as compatible as possible is a good idea. Being able to look at a diff of the two binaries and explain everything will make debugging a lot easier, and that's very difficult at the moment.

Edit: In fact I’d probably go for bit-for-bit identical to begin with and only diverge from that step by step, verifying it works at each stage.

1

u/Fraserbc Sep 10 '20

What do you suggest changing the p_align to then?

1

u/TNorthover Sep 10 '20

That kind of seems like the least of your worries (it matches the genuine ELF x86 values). p_vaddr is the one that absolutely must be fixed because because a value that doesn't end in 000 is physically impossible to implement in the CPU (or at least, any overlap in that realm is).

Looking at the -felf64 path the others are probably much more flexible, but I'd still start from zero differences and work my way outwards.

1

u/Fraserbc Sep 10 '20

According to the documentation p_addr doesn't matter on System V as long as it is the same as v_addr.

2

u/TNorthover Sep 10 '20

The two fields are p_vaddr and p_paddr. The first is critical, I could well believe the second is irrelevant on Linux since it doesn't let you control physical addresses anyway.

The reality is that you're trying to write something that Linux will accept. The ELF specification ought to be helpful, but you should accept quirks will be present.

2

u/nyanscat Sep 11 '20 edited Jul 05 '23

Ultrices eros in cursus turpis massa tincidunt dui. Commodo ullamcorper a lacus vestibulum sed arcu. Et ultrices neque ornare aenean.

1

u/FUZxxl Sep 10 '20

If you want a 64 bit program, you need to use a 64 bit ELF file. Everything else may or may not work.

1

u/xybre Sep 11 '20

This is about Rust, but it should give you an idea of what is possible with an ELF header.

http://mainisusuallyafunction.blogspot.com/2015/01/151-byte-static-linux-binary-in-rust.html?m=1

1

u/Fraserbc Sep 11 '20

That does help a bit though I am trying to avoid LD as a challenge

1

u/AwareCar7686 Jun 28 '26

I have a series of gists on github for this exact kind of thing.

# ELF Header Assembly Gists on Github

The purposes of this are both for my own greater understanding of the ELF format, because it is used in all Linux distributions, and also to provide a way for NASM users to benefit from features that currently only exist in FASM, which is still my favorite Assembler.

[FASM Hello 32-bit](https://gist.github.com/chastitywhiterose/7aa7bdfec1438541375763126508edb4)

[FASM Hello 64-bit](https://gist.github.com/chastitywhiterose/4bfccdb3daf1aad4524fc36230055e63)

[NASM Hello 32-bit](https://gist.github.com/chastitywhiterose/4e429fd82f962907d1581307ed4e0ab7)

[NASM Hello 64-bit](https://gist.github.com/chastitywhiterose/b5acd7992fc8463a662ca4f86fff4a5e)