Is compiling ELF files with MSB flag possible in Linux - linux

Is it possible to compile binary files with MSB endianness in GCC? If so, would they work correctly when executed?

Transferring comments into something resembling an answer.
In part, it depends on the CPU architecture. On SPARC or Power, you'd probably find MSB is the default. On Intel, which is definitely LSB by default, you probably can't.
On Intel. If I somehow altered every ELF header entry to MSB in a little-endian binary, would that execute properly?
No; you'd have to make lots of other changes to the code to give it the slightest chance of working. Basically, every number would have to be reworked from little-endian to big-endian.
Would that include instruction addresses, immediate parameters etc.? I would assume that regardless of the ELF flag, these should remain little-endian.
With just a modicum of further thought, I think there's a very chance high chance that the kernel for Intel will simply decline to execute the MSB ELF executable. It was compiled to expect LSB and knows it doesn't know how to deal with the alternative. To fix that, you'd have to rebuild the kernel and the dynamic loader, ld.so.1. And that's probably just the start of your problems.
On the whole, I would regard this as an exercise in futility. In the absence of information to the contrary, I don't think you need to worry about handling the headers of MSB ELF headers for Intel binaries; they won't exist in practice.

It do not think it is explicitely stated in the System V ABI but AFAIK, the ELF file is expected to be in native endianness (and e_ident[EI_DATA] describes the endianess used):
Byte e_ident[EI_DATA] specifies the data encoding of the
processor-specific data in the object file. The following encodings
are currently defined.
You might expect the processor-specific data to be in the processor endianness. For example, the content of the .got is processor-specific data and you definitely want it to be in native endianness.
On Intel computers, you have to use the ELFDATA2LSB.
From the System V ABI ~ Intel386 Supplement 4th edition:
For file identification in e_ident, the Intel386 architecture
requires the following values.
e_ident[EI_CLASS] = ELFCLASS32
e_ident[EI_DATA] = ELFDATA2LSB
From the System V ABI ~ AMD64 supplement Draft 0.99.6:
For file identification in e_ident, the AMD64 architecture
requires the following values.
e_ident[EI_CLASS] = ELFCLASS64
e_ident[EI_DATA] = ELFDATA2LSB

Related

Can we convert elf from a cpu architecture to another, in linux? [duplicate]

How I can run x86 binaries (for example .exe file) on arm?As I see on Wikipedia,I need to convert binary data for the emulated platform into binary data suitable for execution on the targeted platform.but question is:How I can do it?I need to open file in hex editor and change?Or something else?
To successfully do this, you'd have to do two things.. one relatively easy, one very hard. Neither of which you want to do by hand in a hex editor.
Convert the machine code from x86 to ARM. This is the easy one, because you should be able to map each x86 opcode to one or more ARM opcodes. There are different ways to do this, some more efficient than others, but it can be done with a pretty straightforward mapping.
Remap function calls (and other jumps). This one is hard, because monkeying with the opcodes is going to change all the offsets for the jump and return points. If you have dynamically linked libraries (.so), and we assume that all the libraries are available at exactly the same version in both places (a sketchy assumption at best), you'd have to remap the loads.
It's essentially a machine->machine compiler and linker.
So, can you do it? Sure.
Is it easy? No.
There may be a commercial tool out there, but I'm not aware of it.
You can not do this with a binary;note1 here binary means an object with no symbol information like an elf file. Even with an elf file, this is difficult to impossible. The issue is determining code from data. If you resolve this issue, then you can make de-compilers and other tools.
Even if you haven an elf file, a compiler will insert constants used in the code in the text segment. You have to look at many op-codes and do a reverse basic block to figure out where a function starts and ends.
A better mechanism is to emulate the x86 on the ARM. Here, you can use JIT technology to do the translation as encountered, but you approximately double code space. Also, the code will execute horribly. The ARM has 16 registers and the x86 is register starved (usually it has hidden registers). A compilers big job is to allocate these registers. QEMU is one technology that does this. I am unsure if it goes in the x86 to ARM direction; and it will have a tough job as noted.
Note1: The x86 has an asymmetric op-code sizing. In order to recognize a function prologue and epilogue, you would have to scan an image multiple times. To do this, I think the problem would be something like O(n!) where n is the bytes of the image, and then you might have trouble with in-line assembler and library routines coded in assembler. It maybe possible, but it is extremely hard.
To run an ARM executable on an X86 machine all you need is qemu-user.
Example:
you have busybox compiled for AARCH64 architecture (ARM64) and you want to run it on an X86_64 linux system:
Assuming a static compile, this runs arm64 code on x86 system:
$ qemu-aarch64-static ./busybox
And this runs X86 code on ARM system:
$ qemu-x86_64-static ./busybox
What I am curioous is if there is a way to embed both in a single program.
read x86 binary file as utf-8,then copy from ELF to last character�.Then go to arm binary and delete as you copy with x86.Then copy x86 in clip-board to the head.i tried and it's working.

I am wondering if pie does anything if the aslr is turned off on the system? Or is pie dependant on aslr?

I am also wondering what does pie and what does aslr effect in memory as I understand, aslr randomizes addresses of libc base,stack and heap. And pie randomizes elf base and with that .text,.data,.bss,.rodata...
Is that correct or am I getting it wrong?
PIE requires position-independent code, costing a small amount of performance. (Or a large amount like 15% on ISAs like 32-bit x86 that don't easily support PC-relative addressing). See 32-bit absolute addresses no longer allowed in x86-64 Linux?.
With ASLR disabled, e.g. when running under GDB or with it disabled system-wide, Linux chooses a base address of 0x0000555555555000 to map the executable, so objdump -d addresses relative to the file start like 0x4000 end up at that high virtual address.
A PIE executable is an ELF shared object (like a .so), as opposed to an ELF "executable". An ELF executable has a base address in the ELF headers, set by the linker, so absolute addresses can be hard-coded into the machine code and data without needing relocations for fixups. (That's why there's no way to ASLR a proper ELF executable, only a PIE).
The mechanism that supports PIE was originally just a fun hack of putting an entry point in a library. Later people realized it would be useful for ASLR for static code/data in executables to be possible, so this existing support became official. (Or something like that; I haven't read up on the history.)
But anyway, ASLR is enabled by PIE, but PIE is a thing even with ASLR disabled, if you want the most general non-technical description.

Parameters of files syscall_32.tbl, syscall_64.tbl in build linux kernel

I'm praticing to build a new linux kernel on virtual machine. I have some question about 2 files syscall_32.tbl and syscall_64.tbl in step import parameters of a module in them.
I'm know that file syscall_32.tbl have 5 parameters [number] [abi] [name], [entry point], [compat entry point], and file syscall_64.tbl have 4 without [compat entry point].
I have some questions that I can't find answer for them.
[number]: what is range value of this column. I find out that the numbers are union and increasing sequence. If now I import new with large number (such as 10^6), is it OK?
[abi]: I know that in file syscall_64.tbl, the value of column maybe common, 64, x32. What is meaning of each value? Why is different between them? And why machine 64-bit have value x32 in this column?
[name]: I know that [entry point] and [compat entry point] is used for function to run the syscall. And when user call system call, we don't need call the name, we only use the [number] and kernel space use [entry point] to run. What is a reason for this column ([name])?
Thanks for your view and answer. Sorry for my bad english.
For different binaries to interact, they need to agree on a set of interfaces, e.g. the size of types and layout (padding) of structs. On amd64, GNU/Linux supports three ABIs natively:
i386: For compatibility with x86 32-bit binaries. System calls are defined in syscall_32.tbl
x86_64: Native 64-bit binaries. System calls are defined syscall_64.tbl with abi=64
x32: ILP32 (32-bit int, long and pointers), but with amd64 goodies: e.g. registers are 64-bit and there is more of them than in i386. System calls are defined syscall_64.tbl with abi=x32
A binary's ABI is configured at compilation time (-m32, -m64 and -mx32 respectively for GCC), but the kernel runs in long mode in all three cases and sometimes conversions are necessary to account for ABI differences.
Regarding your questions:
[number]: Size depends on the system call convention. e.g. with int 80h, the system call number is passed through the 32-bit wide eax.
[abi]: "common" system calls can be used for both amd64 ABIs, but some, like those with pointers to structs, need special handling to account for ABI differences.
[name]: Linux provides headers with system call number definitions, e.g.
#define __NR_exit 1. The macro name is generated from the [name] column. See this answer for more information.

Determine dynamically linux OS architecture

Is there is a way to know dynamically Linux architecture, whether it x86-64 or x86?
The Posix standard uname function (implemented in the uname(2) syscall) is dynamically giving you the information about the CPU. You probably want the machine field.
Caution about x86-64 kernels running a 32 bit program (e.g. a 32 bits Debian distribution chroot-ed in a 64 bits Debian, or perhaps a 32 bits ELF binary running on a 64 bits system); I have no idea what they give in that situation; I would imagine some x86_64 in that case, since the kernel does not really know about the binaries and libc of the system.
See also the Linux specific personality(2) syscall.
Google is your friend: http://sourceforge.net/p/predef/wiki/Architectures/
You want to test for the macros __amd64__ and __i386__. Ideally, you don't test the macros at all and write correct, portable code.
You can use lscpu command to list characteristics about CPU.

What's different between compiling in 32bit mode and 64bit mode on 64bit os about execution of ioctl function?

I have a 64 bit Enterprice SuSE 11
I have an application which open a HIDRAW device and operate an ioctl function on it to get raw info from this device like below:
struct hidraw_devinfo devinfo;
int fd = open("/dev/hidraw0", 0);
int ret = ioctl(fd, HIDIOCGRAWINFO, &devinfo);
...
If I compile this program in 64 bit mode there is no error and no problem and when I execute the application the ioctl function works properly.
g++ main.cpp
If I complie this program in 32 bit mode there is also no error and no problem. but when I execute the application the ioctl function return EINVAL error(errno = 22 , Invalid Argument)
g++ -m32 main.cpp
what's the problem?
Note:
struct hidraw_devinfo
{
__u32 bustype;
__s16 vendor;
__s16 product;
}
Linux ioctl definitions and compatibility layers are a fascinating topic I've just bashed my head against.
Typically ioctl definitions use a family of macros _IOW/_IOR et al that take your argument type-name as a reference, along with a magic number and ordinal value that are munged to give you your ioctl argument value (eg HIDIOCGRAWINFO). The type-name is used to encode sizeof(arg_type) into the definition. This means that the type used in user space determines the value generated by the ioctl macro - ie HIDIOCGRAWINFO may vary based on include conditions.
Here is the first point where 32- and 64-bit differ, the sizeof may differ, depending on packing, use of vague data-sizes (eg long), but especially (and unavoidably) if you use a pointer argument. So in this case a 64-bit kernel module what wants to support 32-bit clients needs do define a compatibility argument-type to match the layout of the 32-bit equivalent of the argument type and thus a 32-bit compatible ioctl. These 32-bit equivalent definitions make use of a kernel facility/layer called compat.
In your case the sizeof() is the same so that is not the path you are taking - but its important to understand the whole of what could be happening.
In addition a kernel configuration may define CONFIG_COMPAT which changes the sys-call wrappers (especially the code surrounding the user/kernel interface wrt ioctl) to ease the burden of supporting 32- and 64-bit. Part of this includes a compatibility ioctl callback called ioctl_compat.
What I've seen is with CONFIG_COMPAT defined that 32-bit programs will generate code that delivers ioctls to the ioctl_compat callback, even if it could generate the same ioctl value as 64-bit does (eg in your case). So the driver writer needs to make sure that ioctl_compat handles both the special (different) 32-bit compatible ioctl TYPEs and the normal "64-bit - or unchanged 32-bit" types.
So a kernel-module designed and tested on 32-bit only and 64-bit only systems (without CONFIG_COMPAT) may work for 32- and 64-bit programs, but not for one which supports both.
So looking in HID I see this was added in 2.6.38:
http://lxr.linux.no/#linux+v2.6.38/drivers/hid/hidraw.c#L347
The problem is probably a mismatch between the devinfo structure your program passes to the ioctl function.
I guess your work on a 64 bit system. Thus, your kernel runs in 64 bits, and the kernel module you are talking to (with ioctl) is also 64 bits.
When you compile your user program in 64 bits, the devinfo definition in the kernel module and in the user program is the same.
When you compile your user program in 32 bits, the devinfo definition in the kernel module differs from its definition in your user program. Indeed, in 32 bits, the size of some types changes: mainly long and pointers. Thus, your program create a structure of a certain size, and the kernel module interprets the data it receives differently. The kernel module probably don't understand the value you give to it because it does not look for it at the position you placed it.
The solution is to pay attention to the definition of the devinfo structure so that it has the same binary representation when compiling for 32 bits and for 64 bits.

Resources