I'm recompiling some executable for Android 5.0 as it requires executables to be PIE. I was able to recompile it for ARM with just adding some arguments while configuring (with standalone toolchain):
export CFLAGS="-I/softdev/arm-libs/include -fPIE"
export CPPLAGS="$CPPFLAGS -fPIE"
export CXXLAGS="$CXXFLAGS -fPIE"
export LDFLAGS="-L/softdev/arm-libs/lib -static -fPIE -pie"
No error for ARM:
configure:3406: arm-linux-androideabi-gcc -o conftest -I/softdev/arm-libs/include -fPIE -L/softdev/arm-libs/lib -static -fPIE -pie conftest.c >&5
configure:3410: $? = 0
But i was unable to do the same for x86 as i'm getting error:
export CFLAGS="-I/softdev/x86-libs/include -fPIE"
export CPPLAGS="$CPPFLAGS -fPIE"
export CXXLAGS="$CXXFLAGS -fPIE"
export LDFLAGS="-L/softdev/x86-libs/lib -static -fPIE -pie"
error:
configure:3336: i686-linux-android-gcc -I/softdev/x86-libs/include -fPIE -L/softdev/x86-libs/lib -static -fPIE -pie conftest.c >&5
/softdev/x86-toolchain-gcc4.8/bin/../lib/gcc/i686-linux-android/4.8/../../../../i686-linux-android/bin/ld: fatal error: -pie and -static are incompatible
collect2: error: ld returned 1 exit status
configure:3340: $? = 1
I need executables to be linked statically. What's wrong and how can i fix it?
PS. Also tried using x86 standalone toolchain from android ndk r9d and r10c:
./make-standalone-toolchain.sh --toolchain=x86-4.8 --arch=x86 --install-dir=/softdev/x86-toolchain-gcc4.8-r9d --ndk-dir=/softdev/android-ndk-r9d/ --system=darwin-x86_64
As mentioned by n4sm below gcc-8 or later supports -static-pie which produces a static binary with PIE. Note that is one option not two. If you try to use -static -pie it will not do what you think.
I just did quick test with the fallowing in te.c:
int main( int argc, const char* argv[] )
{
reyurn 0;
}
Running arm-linux-androideabi-gcc -o conftest -static -FPIE -pie te.c produces no error. However file -k conftest outputs
conftest: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), not stripped
readelf -l conftest outputs
Elf file type is DYN (Shared object file)
Entry point 0x500
There are 7 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x00000034 0x00000034 0x000e0 0x000e0 R 0x4
INTERP 0x000114 0x00000114 0x00000114 0x00013 0x00013 R 0x1
[Requesting program interpreter: /system/bin/linker]
...
The presence of the PHDR and INTERP headers indicates that -pie silently overrides -static in the arm compiler. Why this is I don't know but I would consider it a bug that no warning is given when -static and -pie are used together. Instead programmers like you are left with the false impression that the two options can be used to together on arm.
Just to clarify the only behavioral difference here is that the x86 compiler errors on seeing both --static and --pie whereas the arm version silently ignores --static if --pie is given. If only one these is given the behavior is the same for both compilers.
If -pie and -static are both given together, gcc will issue unexpected error.
-pie
Produce a position independent executable on targets that support it. For predictable results, you must also specify the same set of options used for compilation (-fpie, -fPIE, or model suboptions) when you specify this linker option.
-pie actually create a DYN type elf file with INTERP with /system/bin/linker
executable compiled with -pie
-static
On systems that support dynamic linking, this prevents linking with the shared libraries. On other systems, this option has no effect.
-static create a EXEC type elf file with no INTERP
Now it's directly possible with the -static-pie option!
For example:
#include <stdio.h>
/* /tmp/test.c */
int main(int argc, char **argv) {
printf("Hello world!\n");
}
You have just to use the -static-pie option:
gcc /tmp/test.c -static-pie -o /tmp/test
And with readelf we got this:
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000008158 0x0000000000008158 R 0x1000
LOAD 0x0000000000009000 0x0000000000009000 0x0000000000009000
0x000000000009473d 0x000000000009473d R E 0x1000
LOAD 0x000000000009e000 0x000000000009e000 0x000000000009e000
0x00000000000284b8 0x00000000000284b8 R 0x1000
LOAD 0x00000000000c6de0 0x00000000000c7de0 0x00000000000c7de0
0x0000000000005370 0x0000000000006a80 RW 0x1000
DYNAMIC 0x00000000000c9c18 0x00000000000cac18 0x00000000000cac18
0x00000000000001b0 0x00000000000001b0 RW 0x8
NOTE 0x00000000000002e0 0x00000000000002e0 0x00000000000002e0
0x0000000000000020 0x0000000000000020 R 0x8
NOTE 0x0000000000000300 0x0000000000000300 0x0000000000000300
0x0000000000000044 0x0000000000000044 R 0x4
TLS 0x00000000000c6de0 0x00000000000c7de0 0x00000000000c7de0
0x0000000000000020 0x0000000000000060 R 0x8
GNU_PROPERTY 0x00000000000002e0 0x00000000000002e0 0x00000000000002e0
0x0000000000000020 0x0000000000000020 R 0x8
GNU_EH_FRAME 0x00000000000ba130 0x00000000000ba130 0x00000000000ba130
0x0000000000001c8c 0x0000000000001c8c R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x00000000000c6de0 0x00000000000c7de0 0x00000000000c7de0
0x0000000000003220 0x0000000000003220 R 0x1
I don't know since when we can use this option, but for me, I'm using gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Google's NDK tool contain some info about PIE usage.
Visit build/core/build-binary.mk, see line 209. It says:
# enable PIE for executable beyond certain API level, unless "-static"
I guess, it is linux dynamic link principle's limit.
Because Android interpreter (/system/bin/linker) determining which address elf file to be loaded in a static linked file has no interpreter, elf file will be mapped to memory into a fixed address by linux kernel.
Here is a discuss about this change Google issue
If I have any mistake please figure it out:)
Related
Using the arm-none-eabi-gcc compiler from ARM I find that printf("%lf") prints garbage values when the stack is not 8-byte-aligned prior to calling. If I manually align the stack, then it always works:
// This always works, but fails without the get/set_MSP manipulation when
// the MSP is not 8-byte-aligned
unsigned msp = __get_MSP();
__set_MSP(msp & ~7);
// Prints wrong floating-point value when stack is not 8-byte-aligned.
// No difference using %f vs. %lf
printf("%lf\n", 1.234);
__set_MSP(msp);
arm-none-eabi-gcc -v returns:
gcc version 10.2.1 20201103 (release) (GNU Arm Embedded Toolchain 10-2020-q4-major)
and relevant compiler flags are:
-O3 -mcpu=cortex-m7 -mfpu=fpv5-d16 -mfloat-abi=hard -mthumb -Wall -fdata-sections -ffunction-sections -fno-strict-aliasing -std=gnu++17 -fno-rtti -fno-use-cxa-atexit
Can anyone suggest any compiler flags I may be missing (or shouldn't be specifying?) -- or other solutions?
Thanks.
Gcc is just generating code that produces the 8 byte alignment that is mandated by the ARM ABI specification. This is specifically pointed out in ABI for the ArmĀ® Architecture Advisory Note
From Section 3.1 "The need to align SP to a multiple of 8 at conforming call sites"
In return for preserving the natural alignment of data, conforming code
is permitted to rely on that alignment. To support aligning data allocated on the stack, the stack pointer (SP) is required to be 8-byte aligned on entry to a conforming function...
For a long time I had not programmed with C and Assembler (about 2 years). Now I have decided to start again but I would like to do something much more complicated. I thought about creating a simple kernel. Now I found this source code on the internet:
boot.asm:
global loader
extern kernel_main
MAGIC equ 0xbad
FLAGS equ 0x3
CHECKSUM equ -(MAGIC+FLAGS)
section .text
align 4
dd MAGIC
dd FLAGS
dd CHECKSUM
loader:
call kernel_main
cli
quit:
hlt
jmp quit
kernel.c:
void print(char *text) {
char *memory = (char*)0xb8000;
while(*text) {
*memory++ = *text++;
*memory++ = 0x3;
}
}
void kernel_main() {
print("My cat sometimes smells like cafe. I love it.");
}
linker.ld:
ENTRY(loader)
SECTIONS {
. = 0x100000;
.text : { *(.text) }
}
Note: I compiled the C file with "GCC" and the Assembler file with "NASM".
If I try this command:
ld -T linker.ld -elf_i386 -o final.bin boot.o kernel.o
It says: "boot.asm:(.text+0xd): undefined reference to `kernel_main'".
How can I fix this?
Im working on windows and do not want to run a VM with Linux or anything. Thanks in advance!
Edit:
This is my GCC command:
gcc -m32 -o kernel.o srckernel.c -nostdlib -nostartfiles -nodefaultlibs
This is my NASM command:
nasm -f elf32 -o boot.o boot.asm
There are a number of things wrong. I will assume given the error:
boot.asm:(.text+0xd): undefined reference to kernel_main
that you are not using an ELF cross compiler and that you are using a GCC compiler that generates native Windows executables (ie. Cygwin and MinGW). I highly recommend the use of an i686 (or x86_64) ELF cross compiler for OS Development especially on Windows.
Your primary problems are:
The option -elf_i386 was probably meant to be -melf_i386 however that is even incorrect. With a GCC that targets windows you will want to use -mi386pe to output as Win32 PE/COFF format. The Windows GCC linker usually doesn't know how to generate ELF executables. I also recommend using the -N option when using LD to output i386pe format. Change your linker command to be:
ld -N -T linker.ld -mi386pe -o final.bin boot.o kernel.o
With Win32 PE/COFF objects1: functions that use the CDECL calling convention have to have an underscore (_) prepended to them. kernel_main needs to be _kernel_main. You need to change these lines in boot.asm from:
extern kernel_main
call kernel_main
to:
extern _kernel_main
call _kernel_main
You don't show how you compile kernel.c and how you assemble boot.asm but they should look similar to:
nasm -f win32 boot.asm -o boot.o
gcc -g -c -m32 -ffreestanding kernel.c -o kernel.o
When you do manage to generate final.bin it is a Windows PE executable. The Multiboot specification requires ELF executables. After linking to final.bin with LD, you can convert final.bin to ELF format with:
objcopy -O elf32-i386 final.bin final.elf
final.elf should now be usable as a Multiboot ELF executable.
There is an issue with your Multiboot header in boot.asm. The Multiboot magic value is 0x1badb002 not 0xbad. Since you haven't specified a video configuration in your Multiboot header FLAGS should not have Bit 1 set, FLAGS should be 0x1 instead of 0x3. Change your Multiboot header from:
MAGIC equ 0xbad
FLAGS equ 0x3
to:
MAGIC equ 0x1badb002
FLAGS equ 0x1
With the changes noted above I was able to generate an ELF executable called final.elf. When run with QEMU using the command:
qemu-system-i386 -kernel final.elf
The output I get is:
Footnotes:
1The extra underscore on function names doesn't apply when generating Win64 PE32+ objects.
I am trying to compile some GAS code for a project using the GCC gnu compiler. Here is how I am compiling it:
gcc -c boot.s -o boot.o -fPIC
After I compile my kernel.c file with the -fPIC argument, I try to link it with this command:
gcc -N -T linker.ld -o Slack\ Berry.bin -ffreestanding -nostdlib kernel.o boot.o -lgcc
It comes up with:
/usr/bin/ld: boot.o: relocation R_X86_64_32 against '.multiboot' can not be used when making a PIE object; recompile with -fPIC
This leads me to think that it is not compiling my GAS code with -fPIC. How can I fix this?
First of all you probly need -fPIE rather than -fPIC. -fPIE allows compiler to generate more efficient code but can only be used for code that's part of main executable (not shared library).
Now both -fPIC and -fPIE are compiler-only flags and are not passed to assembler. You'll need to explicitly use PIC-specific mnemonics in your assembly code instead of position-dependent calls and branches e.g instead of
movq $bar, %rdx
use
movq bar#GOTPCREL(%rip), %rdx
(normally to get the syntax I need I just run gcc -fPIE -S -o- on matching C snippet).
Recompile with -fPIC only applies if the asm was generated by a compiler, not written by hand. It has no effect on how asm is assembled into machine code.
The problem is that your PIE executable can't be linked with 32-bit absolute addresses. (Did you mean to make a PIE instead of a static position-dependent executable)?
You don't need the full shared-library stuff for referencing symbols in another library or the main executable (like #yugr's answer shows how to do). Your freestanding kernel may not even have a GOT or PLT, and definitely shouldn't use them for internal symbols.
The only change needed is lea bar(%rip), %rdx, a RIP-relative LEA instead of a mov $imm32, %r/m64. (movabs would work to, but be larger and usually slower.)
Or, if you actually meant to build with -static and create an executable that will be loaded at a fixed address in the low 32 bits of address space, you should use mov $bar, %edx to get a 5-byte mov $imm32, %r32 encoding instead of 7-byte mov $sign_extended_imm32, %r/m64 or a 7-byte LEA. See also Difference between movq and movabsq in x86-64
I'm trying to make an executable out of two files:
vm.o, which contains a bunch of non-relocatable functions,
launcher.c, which has a main function that starts my vm.
vm.o is an elf32 file, with a .text section of code that expects to be loaded at 0x401000, as shown by objdump -x vm.o.
...
SYMBOL TABLE:
00401000 l d .text 00000000 .text
00401000 g .text 00000000 _binary_vm_o_start
....
I'm running gcc like this:
gcc -no-pie -m32 -o vm vm.o loader.c -ldl
But the generated file ignores the positions specified in vm.o. If I do
gcc -no-pie -m32 -o vm vm.o loader.c -ldl -Ttext 0x401000
I get close, but _start is put at 0x401000 and my vm.o is put at 0x4010fb.
Is there a simple way to tell gcc to put the .text section of vm.o in the desired position? I know a way of doing this with ld, but I'd rather use gcc to link.
I finally found a workaround that, while not exactly the same, works very well. I can just rename my .text section in vm.o (so that it does not get merged with the other .text ones), and then make gcc put that particular section at the desired position:
# change the name of .text section to .vm
objcopy --rename-section .text=.vm,contents,alloc,load,code vm.o vm-temp.o
# compile setting .vm to 0x401000 (no-pie means no position-independent code)
gcc -no-pie -m32 -o vm vm-temp.o loader.c -Wl,--section-start=.vm=0x401000 -ldl
note that the -T in gcc only works for changing the address of .text but doesn't for other sections.
I'm following a assembly book which uses the yasm assembler and ld linker. I'm on OSX 10.12 and I'm trying to assembly to Mach-O format. Unfortunately, I'm receiving a segmentation fault. This is the original .asm file:
BITS 64
segment .data
a dd 4
segment .bss
g resd 1
segment .text
global start
start:
push rbp
mov rbp, rsp
sub rsp, 16
xor eax, eax
leave
ret
I compile it:
yasm -f macho64 -m amd64 -l memory.lst -o memory.o memory.asm
link it:
ld memory.o -o memory
and run it in lldb, I receive this error:
thread #1: tid = 0xb3b4b, 0x0000000000000001, stop reason = EXC_BAD_ACCESS (code=1, address=0x1)
frame #0: 0x0000000000000001
error: error reading data from section __PAGEZERO
In lldb, I ran 'target modules dump sections', and I see that it's __PAGEZERO segment is defined as so:
[0x0000000000000000-0x0000000000001000) --- memory.__PAGEZERO
I looked at a normal Mach-O binary built with clang, and the __PAGEZERO segment looks like this:
[0x0000000000000000-0x0000000100000000) --- test.__PAGEZERO
I then noticed that it's actually the linker that creates the PAGEZERO segment. I believe clang uses a special linker called 'lld'. My question is:
Is my error actually caused by reading from PAGEZERO.
If so, can I tell my linker (ld) to define PAGEZERO in the correct size?
SOLVED: I changed the link command to:
ld memory.o -macosx_version_min 10.12 -lSystem -o memory
This doesn't change the PAGEZERO size, so I'm not sure how it fixed it, but it works now.