Lei Mao bio photo

Lei Mao

Machine Learning, Artificial Intelligence. On the Move.

Twitter Facebook LinkedIn GitHub   G. Scholar E-Mail RSS

Introduction

Recently I found the executables I compiled would not have the traditional Ubuntu executable icon as it used to have. As you can see from the following figure, the left one is what I got recently, RGB2Grey was supposed to be an executable but its icon just looked exactly the same to an text file. The right one is what I used to get, the executable file RGB2Grey stands out apparently. Although both executables run fine without any problem, as a perfectionist, I don’t like it when I can’t see the icon.

Executable Icons Gone

I did some simple Googling and research, and found that it is due to the Position Independent Code (PIC) or Position Independent Executables (PIE) toggles when you compile your program. Then what is PIC and PIE?

PIC and PIE

Position independent means memory position independent. PIC and PIE generally means almost the same thing, while PIC emphasize on libraries and PIE emphasize on executables. In old days, programs were position dependent, i.e., after compile, the program has to be loaded into, and run from, a particular absolute address on memory. Apparently this is not a good idea if you have a lot of position dependent programs to run and they are not scheduled very well by either human or computer.


Nowadays, say you have 10 non-PIC libraries or non-PIE executables, and they were mapped to some different places on physical memory using virtual memory. The virtual memory address for different programs could be the same because they are virtual, say one program has virtual memory address from 0 to 255 and another program has virtual memory address from 0 to 511, but they are mapped to different addresses on physical memory. When you start to run your 11th library or executable, it was firstly created on virtual memory, then this piece of virtual memory will be mapped to physical memory. If the memory size between the occupied physical memories are too small for the new program, the operating system will not assign the virtual memory of the new program there. Because of these, if you have a lot of non-PIC libraries or non-PIE executables running, the memory usage will be pool. In the even earlier days, there is no virtual memory and programs do collide on physical memories, and computer crashes. But this is not going to happen any more on a modern computer using modern operating system, we are not going to talk about it here.


So how to make good use of memory? PIC or PIE! Now the memory occupancy of libraries and executables on the virtual memories will be mapped to scattered locations on physical memory. There is always a table keep tracking the memory offsets of these memory segments so that your program would always find the correct address. That is to say, a position-independent program could be loaded at any address on (physical) memory. Otherwise, without PIC, it has to be at least consecutive on physical memory.


PIC and PIE programs are generally slower and bigger compared to non-PIC and non-PIE prgrams, because obviously calculating memory addresses take time. If we have large memories, to get better performance, we like to have non-PIC libraries and non-PIE executables. But it seems that in many scenarios you will use PIC at least for the shared libraries because PIC ensure that the same code can be used by multiple process which will map the same physical memory to various virtual addresses when we build shared library .so files.

Compile With and Without PIC/PIE

It turns out that newer versions of GNC compilers starts to compile with PIC/PIE by default. The executable program compiled using PIE will not have executable icon in Ubuntu. That is why I started not to see icons if I compile regularly. After turning off PIE, the icon of the executable looks normal. Here are some ways to turn-on or turn-off PIE when you compile. Instruction on how to turn-on or turn-off PIC should be similar and not hard to find.

Old GCC

$ gcc main.c -o main # No PIE
$ gcc main.c -o main -fPIE # PIE

New GCC

$ gcc main.c -o main -no-pie  # No PIE
$ gcc main.c -o main # PIE

Old CMake

cmake_minimum_required( VERSION 3.10.0 )

project( RGB2Grey VERSION 1.0.0 )

find_package( OpenCV REQUIRED )
find_package( CUDA REQUIRED )

# No PIE flag
set ( CMAKE_CXX_FLAGS "-no-pie" )

include_directories( ${OpenCV_INCLUDE_DIRS} ${CUDA_INCLUDE_DIRS} )
cuda_add_executable( ${PROJECT_NAME} main.cpp utils.cpp grey.cu )
target_link_libraries( ${PROJECT_NAME} ${OpenCV_LIBRARIES} ${CUDA_LIBRARIES})

New CMake

cmake_minimum_required( VERSION 3.10.0 )

project( RGB2Grey VERSION 1.0.0 )

find_package( OpenCV REQUIRED )
find_package( CUDA REQUIRED )

# Need to have if want PIE
include(CheckPIESupported)
check_pie_supported()

include_directories( ${OpenCV_INCLUDE_DIRS} ${CUDA_INCLUDE_DIRS} )
cuda_add_executable( ${PROJECT_NAME} main.cpp utils.cpp grey.cu )
target_link_libraries( ${PROJECT_NAME} ${OpenCV_LIBRARIES} ${CUDA_LIBRARIES})

# PIE flag TRUE/FALSE
set_property(TARGET ${PROJECT_NAME} PROPERTY POSITION_INDEPENDENT_CODE FALSE)

Final Remarks

I started to see that PIC and PIE actually have more depth than what initially they are seen. Honestly I do not have too much background in computer systems and I cannot guarantee what I said above regarding the theory is correct. But at least PIC and PIE are the things which are worth being aware.

References