I am exploring the Linux Kernel code and came across this line of code:
#define __init_task_data __attribute__((__section__(".data..init_task"))).
I know that something like:
int x __attribute__((__section__("section"))) = 10;
is an attribute of gcc which would put the symbol of x into the section "section" of the compiled process image. However when I try to specify ".data..init_task" as the section, my variable gets put into the .data section. Here is my code:
int apple __attribute__((__section__(".data..init_task"))) = 10;
Compiled with:
gcc test.c
Disassembled with:
objdump -D a.out
My variable "apple" appears under the .data section, there is no section ".data..init_task" which is what has stumped me.
Related
I wish to call OCaml code through C++ by compiling OCaml to a static or shared library that contains a C interface. This page seems to explain how to create a C interface for OCaml. But how do I do it and compile it? And how do I obtain the .h file to load in my C++ code?
Also, could someone explain to be this part:
The OCaml runtime system comprises three main parts: the bytecode
interpreter, the memory manager, and a set of C functions that
implement the primitive operations. Some bytecode instructions are
provided to call these C functions, designated by their offset in a
table of functions (the table of primitives).
I thougth OCaml could be compiled to native machine language. Why it is compiled to bytecode and interpreted at runtime? Is it always like that, or only for OCaml libraries compiled with C interface?
Most of that page describes how to call C from OCaml. You want to do the reverse, which is described in Advanced Topics: callbacks from C to OCaml, closer to the bottom of the page.
When you do native compilation there is no bytecode involved, just as you say. The native compiler (ocamlopt) produces ordinary object (.o in Unix) files and extra files containing OCaml metadata.
If you look at Advanced Example with callbacks, you'll see an example where the main program is in C, with calls to two functions defined in OCaml. Things should work similarly in C++. (I have only done this in C myself, however.)
Update
Here is the worked-out example using the code from Advanced example with callbacks. I am running this code on Ubuntu 18.04.4 (x86_64).
The OCaml code looks like this:
$ cat mod.ml
let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 1)
let format_result n = Printf.sprintf "Result is: %d\n" n
let () = Callback.register "fib" fib
let () = Callback.register "format_result" format_result
Compile this code and ask for a complete object file:
$ ocamlopt -output-obj -o bigmod.o mod.ml
Rename the C code to modwrap.cc. (The code is given in the OCaml manual section.)
$ head -6 modwrap.cc
#include <stdio.h>
#include <string.h>
#include <caml/mlvalues.h>
#include <caml/callback.h>
int fib(int n)
Note that the OCaml include files are conditionalized as to whether they're being included from C or C++ (as are almost all header files these days).
The main function from the OCaml manual section is also valid C++; rename it to main.cc:
$ head -7 main.cc
#include <stdio.h>
#include <caml/callback.h>
extern int fib(int n);
extern char * format_result(int n);
int main(int argc, char ** argv)
Now compile and link everything:
$ g++ -c modwrap.cc
$ g++ -o myprog -I $(ocamlopt -where) \
main.cc modwrap.o bigmod.o $(ocamlopt -where)/libasmrun.a -ldl
$
Now run the program
$ ./myprog
fib(10) = Result is: 89
There is no automatic generation of header files. In this example the extern lines of main.cc are the header file in essence. If you want a header file you'll have to write something like this yourself.
Update 2
Here are the commands for creating an actual static library containing the OCaml functions and their wrappers. This assumes that you have done the compiles above to create bigmod.o and modwrap.o:
$ cp $(ocamlopt -where)/libasmrun.a libmyoc.a
$ ar r libmyoc.a bigmod.o modwrap.o
Now you can use this library in your C++ code (represented by main.cc):
$ g++ -o myprog -I $(ocamlopt -where) main.cc -L . -lmyoc -ldl
$ ./myprog
fib(10) = Result is: 89
Update 3
(I updated the above commands to work on Unbuntu.)
I've been writing an OS using this tutorial. I am at the part where
the boot loader is completed and C is used for programming (and then linked together ...). But that just as a note, I believe the problem I have is related to gcc.
I build an i386-elf cross compiler for the OS. And everything works fine, I can execute my code everything works. Except that all global variables are initialized zero, although I provided a default value.
int test_var = 1234;
// yes, void main() is correct (the boot-loader will call this)
void main() {}
If I debug this code with GDB, I get: (gcc-7.1.0, target: i328-elf)
(gdb) b main
Breakpoint 1 at 0x1554: file src/kernel/main.c, line 11.
(gdb) c
Continuing.
Breakpoint 1, main () at src/kernel/main.c:11
11 void main() {
(gdb) p test_var
$1 = 0
If i run the same code on my local machine (gcc-6.3.0, target: x86_64), it prints 1234.
My question is: Did I misconfigure gcc, is this a mistake in my OS, is this a known problem? I couldn't find anything about it.
My entire source-code: link
I use the following commands to compile my stuff:
# ...
i386-elf-gcc -g -ffreestanding -Iinclude/ -c src/kernel/main.c -o out/kernel/main.o
# ...
i386-elf-ld -e 0x1000 -Ttext 0x1000 -o out/kernel.elf out/kernel_entry.o out/kernel/main.o # some other stuff ...
i386-elf-objcopy -O binary out/kernel.elf out/kernel.bin
cat out/boot.bin out/kernel.bin > out/os.bin
qemu-system-i386 -drive "format=raw,file=out/os.bin"
EDIT: As #EugeneSh. suggested here some logic to make sure, that it's not removed:
#include <cpu/types.h>
#include <cpu/isr.h>
#include <kernel/print.h>
#include <driver/vga.h>
int test_var = 1234;
void main() {
vga_text_init();
switch (test_var) {
case 1234: print("That's correct"); break;
case 0: print("It's zero"); break;
// I don't have a method like atoi() in place, I would use
// GDB to get the value
default: print("It's something else");
}
}
Sadly it prints It's zero
Compiler never clears uninitialized global variables to zero, its logic in built inside loader,
So when you allocate memory for data segment then it size contains bss section also. So you have to check bss section offset, alignment & size withing data segment and memset() them to '0'.
As you are writing your OS so may be all the library routines are not available so better write memset() function using assembly.
I wrote the simple C program (test.c) below:-
#include<stdio.h>
int main()
{
return 0;
}
and executed the follwing to understand size changes in .bss segment.
gcc test.c -o test
size test
The output came out as:-
text data bss dec hex filename
1115 552 8 1675 68b test
I didn't declare anything globally or of static scope. So please explain why the bss segment size is of 8 bytes.
I made the following change:-
#include<stdio.h>
int x; //declared global variable
int main()
{
return 0;
}
But to my surprise, the output was same as previous:-
text data bss dec hex filename
1115 552 8 1675 68b test
Please explain.
I then initialized the global:-
#include<stdio.h>
int x=67; //initialized global variable
int main()
{
return 0;
}
The data segment size increased as expected, but I didn't expect the size of bss segment to reduce to 4 (on the contrary to 8 when nothing was declared). Please explain.
text data bss dec hex filename
1115 556 4 1675 68b test
I also tried the comands objdump, and nm, but they too showed variable x occupying .bss (in 2nd case). However, no change in bss size is shown upon size command.
I followed the procedure according to:
http://codingfox.com/10-7-memory-segments-code-data-bss/
where the outputs are coming perfectly as expected.
When you compile a simple main program you are also linking startup code.
This code is responsible, among other things, to init bss.
That code is the code that "uses" 8 bytes you are seeing in .bss section.
You can strip that code using -nostartfiles gcc option:
-nostartfiles
Do not use the standard system startup files when linking. The standard system libraries are used normally, unless -nostdlib or -nodefaultlibs is used
To make a test use the following code
#include<stdio.h>
int _start()
{
return 0;
}
and compile it with
gcc -nostartfiles test.c
Youll see .bss set to 0
text data bss dec hex filename
206 224 0 430 1ae test
Your first two snippets are identical since you aren't using the variable x.
Try this
#include<stdio.h>
volatile int x;
int main()
{
x = 1;
return 0;
}
and you should see a change in .bss size.
Please note that those 4/8 bytes are something inside the start-up code. What it is and why it varies in size isn't possible to tell without digging into all the details of mentioned start-up code.
I am trying to understand how to set the value of a string in the rodata segment as loading it using an environment variable gives me issues.
I want to externally set a constant string in the rodata section. This function should be independent of the code executed. So, when I do
"objdump -c foo"
the rodata section must enlist this string without the file foo.c having to do it.
How do I set a constant in the .rodata section ?
Edit: Linux OS and using GCC
I cannot use an environment var as that would mean that the c code is modified, I want the c code untouched and add the constant, say "Goo" to the rodata segment.
Then you need to write a program that lets you modify the binary file.
Read the ELF file specifications.
Then write a program that modifies the ELF program and section headers and adds the data to the .rodata section.
I've managed to write a small bash script that does more or less what I think you want.
First let's consider this sample program:
test.c
#include <stdio.h>
const char message[1024] = "world";
int main()
{
printf("hello %s\n", message);
}
The target variable will be message. Note that I will not change the size of the variable, that would be a mess, you be careful to reserve as much memory as you will ever need.
Now the script:
patchsym
#!/bin/bash
# usage: patchsym PROGRAM SYMBOL < NEWCONTENT
EXE="$1"
SYMBOL="$2"
OFFS=$((0x$(objdump -t "$EXE" | grep " $SYMBOL$" | cut -d ' ' -f 1)))
OFFS=2176
dd of="$EXE" bs=1 seek=$OFFS conv=notrunc
The new message content will be:
newmsg
universe^#
(where ^# is actually a NUL character).
Now just do:
$ gcc test.c -o test
$ ./test
hello world
$ ./patchsym test message < newmsg
$ ./test
hello universe
The RealView ARM C Compiler supports placing a variable at a given memory address using the variable attribute at(address):
int var __attribute__((at(0x40001000)));
var = 4; // changes the memory located at 0x40001000
Does GCC have a similar variable attribute?
I don't know, but you can easily create a workaround like this:
int *var = (int*)0x40001000;
*var = 4;
It's not exactly the same thing, but in most situations a perfect substitute. It will work with any compiler, not just GCC.
If you use GCC, I assume you also use GNU ld (although it is not a certainty, of course) and ld has support for placing variables wherever you want them.
I imagine letting the linker do that job is pretty common.
Inspired by answer by #rib, I'll add that if the absolute address is for some control register, I'd add volatile to the pointer definition. If it is just RAM, it doesn't matter.
You could use the section attributes and an ld linker script to define the desired address for that section. This is probably messier than your alternatives, but it is an option.
Minimal runnable linker script example
The technique was mentioned at: https://stackoverflow.com/a/4081574/895245 but now I will now provide a concrete example.
main.c
#include <stdio.h>
int myvar __attribute__((section(".mySection"))) = 0x9ABCDEF0;
int main(void) {
printf("adr %p\n", (void*)&myvar);
printf("val 0x%x\n", myvar);
myvar = 0;
printf("val 0x%x\n", myvar);
return 0;
}
link.ld
SECTIONS
{
.mySegment 0x12345678 : {KEEP(*(.mySection))}
}
GitHub upstream.
Compile and run:
gcc -fno-pie -no-pie -o main.out -std=c99 -Wall -Wextra -pedantic link.ld main.c
./main.out
Output:
adr 0x12345678
val 0x9abcdef0
val 0x0
So we see that it was put at the desired address.
I cannot find where this is documented in the GCC manual, but the following syntax:
gcc link.ld main.c
seems to append the given linker script to the default one that would be used.
-fno-pie -no-pie is required, because the Ubuntu toolchain is now configured to generate PIE executables by default, which leads the Linux kernel to place the executable on a different address every time, which messes with our experiment. See also: What is the -fPIE option for position-independent executables in gcc and ld?
TODO: compilation produces a warning:
/usr/bin/x86_64-linux-gnu-ld: warning: link.ld contains output sections; did you forget -T?
Am I doing something wrong? How to get rid of it? See also: How to remove warning: link.res contains output sections; did you forget -T?
Tested on Ubuntu 18.10, GCC 8.2.0.
You answered your question,
In your link above it states:
With the GNU GCC Compiler you may use only pointer definitions to access absolute memory locations. For example:
#define IOPIN0 (*((volatile unsigned long *) 0xE0028000))
IOPIN0 = 0x4;
Btw http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Variable-Attributes.html#Variable%20Attributes
Here is one solution that actually reserves space at a fixed address in memory without having to edit the linker file:
extern const uint8_t dev_serial[12];
asm(".equ dev_serial, 0x1FFFF7E8");
/* or asm("dev_serial = 0x1FFFF7E8"); */
...
for (i = 0 ; i < sizeof(dev_serial); i++)
printf((char *)"%02x ", dev_serial[i]);
In GCC you can place variable into specific section:
__attribute__((section (".foo"))) static uint8_t * _rxBuffer;
or
static uint8_t * _rxBuffer __attribute__((section (".foo")));
and then specify address of the section in GNU Linker Memory Settings:
.foo=0x800000
I had a similar issue. I wanted to allocate a variable in my defined section at a special offset. In the same time I wanted the code to be portable (no explicit memory address in my C code). So I defined the RAM section in the linker script, and defined an array with the same length of my section (.noinit section is 0x0F length).
uint8_t no_init_sec[0x0f] __attribute__ ((section (".noinit")));
This array maps all locations of this section. This solution is not suitable when the section is large as the unused locations in the allocated array will be a wasted space in the data memory.
The right answer to my opinion is the Minimal runnable linker script example one.
However, there was something not mentioned there:
If the variable is not used in code (e.g. the variable holds read-only data such as version...), it is necessary to add the 'used' attribute.
Refer to my answer at https://stackoverflow.com/a/75468786/3887115.