Hello Guys I am starting the voyage of debugging the code, and ran the following commands as per the book just for some analysis for the source code below
// hello_world-1.c
#include <stdio.h>
int main(void)
{
printf("hello world\n");
return 0;
gcc -Wall -Wextra -c hello_world-1.c // What is wall and wextra here ?
$ size hello_world-1 hello_world-1.o
text data bss dec hex filename
916 256 4 1176 498 hello_world-1
48 0 0 48 30 hello_world-1.o
$ objdump -h hello_world-1.o
hello_world-1.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000023 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000000 00000000 00000000 00000058 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000058 2**2
ALLOC
3 .rodata 0000000d 00000000 00000000 00000058 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .note.GNU-stack 00000000 00000000 00000000 00000065 2**0
CONTENTS, READONLY
5 .comment 0000001b 00000000 00000000 00000065 2**0
CONTENTS, READONLY
48 0 0 48 30 hello_world-1.o
I have some question here
1) There are no global variables in hello_world-1.c. Then why the size reports that the data and bss segments have zero length for the object file but non zero for the executable?
2) Why size and objdump report different sizes for the text segment?
Object file consists of .text (i.e. binary CPU instructions), .rodata (read-only data - "hello world"\10\0 - 13 bytes total) and .comment (additional linking information).
Executable file consists of the same minus .comment plus standard library stuff plus import dynamic library data, if any.
Standard library adds at least startup code, which makes executable bigger. So your difference is: executable .text = .object text + startup code + stdlibrary code (if static linking).
regarding your question:
"gcc -Wall -Wextra -c hello_world-1.c // What is wall and wextra here ?"
(note capitalization counts)
-Wall tell the compiler to enable most warnings
-Wextra tell the compiler to enable even more warnings
-c tells the compiler to only compile, not link.
because no '-o objfilename.o' parameter was included,
the compiler will ouput an object file with the same name as the input file, with a '.o' extension.
suggest always include the '-o objfilename.o' parameter explicitly
suggest performing some online googling for such things, wherein you would have found pages similar to :
https://gcc.gnu.org/onlinedocs/gcc-3.0.4/gcc_3.html
here is a copy of the man page for 'size'
SIZE(1) GNU Development Tools SIZE(1)
NAME
size - list section sizes and total size.
SYNOPSIS
size [-A|-B|--format=compatibility]
[--help]
[-d|-o|-x|--radix=number]
[--common]
[-t|--totals]
[--target=bfdname] [-V|--version]
[objfile...]
DESCRIPTION
The GNU size utility lists the section sizes---and the total size---for
each of the object or archive files objfile in its argument list. By
default, one line of output is generated for each object file or each
module in an archive.
objfile... are the object files to be examined. If none are specified,
the file "a.out" will be used.
OPTIONS
The command line options have the following meanings:
-A
-B
--format=compatibility
Using one of these options, you can choose whether the output from
GNU size resembles output from System V size (using -A, or
--format=sysv), or Berkeley size (using -B, or --format=berkeley).
The default is the one-line format similar to Berkeley's.
Here is an example of the Berkeley (default) format of output from
size:
$ size --format=Berkeley ranlib size
text data bss dec hex filename
294880 81920 11592 388392 5ed28 ranlib
294880 81920 11888 388688 5ee50 size
This is the same data, but displayed closer to System V
conventions:
$ size --format=SysV ranlib size
ranlib :
section size addr
.text 294880 8192
.data 81920 303104
.bss 11592 385024
Total 388392
size :
section size addr
.text 294880 8192
.data 81920 303104
.bss 11888 385024
Total 388688
--help
Show a summary of acceptable arguments and options.
-d
-o
-x
--radix=number
Using one of these options, you can control whether the size of
each section is given in decimal (-d, or --radix=10); octal (-o, or
--radix=8); or hexadecimal (-x, or --radix=16). In --radix=number,
only the three values (8, 10, 16) are supported. The total size is
always given in two radices; decimal and hexadecimal for -d or -x
output, or octal and hexadecimal if you're using -o.
--common
Print total size of common symbols in each file. When using
Berkeley format these are included in the bss size.
-t
--totals
Show totals of all objects listed (Berkeley format listing mode
only).
--target=bfdname
Specify that the object-code format for objfile is bfdname. This
option may not be necessary; size can automatically recognize many
formats.
-V
--version
Display the version number of size.
#file
Read command-line options from file. The options read are inserted
in place of the original #file option. If file does not exist, or
cannot be read, then the option will be treated literally, and not
removed.
Options in file are separated by whitespace. A whitespace
character may be included in an option by surrounding the entire
option in either single or double quotes. Any character (including
a backslash) may be included by prefixing the character to be
included with a backslash. The file may itself contain additional
#file options; any such options will be processed recursively.
SEE ALSO
ar(1), objdump(1), readelf(1), and the Info entries for binutils.
COPYRIGHT
Copyright (c) 1991-2013 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; with no
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
Texts. A copy of the license is included in the section entitled "GNU
Free Documentation License".
binutils-2.23.91 2013-11-18 SIZE(1)
Related
I learned from this link Why is address 0x400000 chosen as a start of text segment in x86_64 ABI? that 64-bit Linux process start address by default should be 0x400000, but on my Ubuntu, I only found my bash process starts from a very high base address (0x55971cea6000).
Any one knows why? and how does dynamic linker choose the start address for a 64-bit process?
$ uname -r
5.15.0-25-generic
$ cat /etc/*release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04 LTS"
...
$ file /usr/bin/bash
/usr/bin/bash: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=33a5554034feb2af38e8c75872058883b2988bc5, for GNU/Linux 3.2.0, stripped
$ ld -verbose | grep -i text-segment
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
$ cat maps
55971ce77000-55971cea6000 r--p 00000000 08:02 153 /usr/bin/bash
55971cea6000-55971cf85000 r-xp 0002f000 08:02 153 /usr/bin/bash
55971cf85000-55971cfbf000 r--p 0010e000 08:02 153 /usr/bin/bash
55971cfc0000-55971cfc4000 r--p 00148000 08:02 153 /usr/bin/bash
55971cfc4000-55971cfcd000 rw-p 0014c000 08:02 153 /usr/bin/bash
55971cfcd000-55971cfd8000 rw-p 00000000 00:00 0
...
$ readelf -h /usr/bin/bash
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Position-Independent Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x32eb0
Start of program headers: 64 (bytes into file)
Start of section headers: 1394600 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 13
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 29
I learned from this link Why is address 0x400000 chosen as a start of text segment in x86_64
That address is used for executables (ELF type ET_EXEC).
I only found my bash process starts from a very high base address (0x55971cea6000). Any one knows why?
Because your bash is (newer) position-independent executable (ELF type ET_DYN). It behaves much like a shared library, and is relocated to random address at runtime.
The 0x55971cea6000 address you found will vary from one execution to another. In contrast, ET_EXEC executables can only run correctly when loaded at their "linked at" address (typically 0x400000).
how does dynamic linker choose the start address for a 64-bit process?
The dynamic linker doesn't choose the start address of the executable -- the kernel does (by the time the dynamic linker starts running, the executable has already been mmaped into memory).
The kernel looks at the .e_type in the ELF header and .p_vaddr field of the first program header and goes from there. IFF .e_type == ET_EXEC, then the kernel maps executable segments at their .p_vaddr addresses. For ET_DYN, if ASLR is in effect, the kernel performs mmaps at a random address.
In an embedded environment i want to convey information about a special part
of memory (start address and length) from the build process to the program
loader. My idea is to let linker create an output section similar to .bss,
i.e. that section should not occupy space in the elf file and should have flags
like the .bss section. I came to this idea since i am already using a customized
linker script.
When processing the elf file, my costumized loader could recognize this section
by a magic name and use the sections size and VMA as the description for the
special part of memory.
When i say it should be similar to .bss, i mean the output of objdump -h
should be similar to this:
Sections:
Idx Name Size VMA LMA File off Algn
...
7 .bss 00000204 10204c9c 10204c9c 00005c40 2**2
ALLOC
...
I guess it is important that here only the flag ALLOC is present, but not LOAD
or CONTENTS.
Can this be achieved with some instructions in the linker script?
If so, what are those instructions?
Browsing through similar questions here at stackoverflow and the ld documentation showed that the solution is quite simple:
.special_start = 0x20000000;
.special_size = 0x10000000;
.special .special_start (NOLOAD) :
{
. = . + .special_size;
}
gives this ouput from objdump -h:
Sections:
Idx Name Size VMA LMA File off Algn
...
6 .sbss 0000005c 10204c40 10204c40 00005c40 2**2
ALLOC, SMALL_DATA
7 .bss 00000204 10204c9c 10204c9c 00005c40 2**2
ALLOC
8 .special 10000000 20000000 20000000 00006000 2**0
ALLOC
...
I'm trying to write an executable where the .text section is located in a specific location. I wrote the following linker script:
base_address = 0x123456789AB;
SECTIONS
{
ENTRY(_start)
. = base_address;
.text : { *(.text); }
}
However when I look at the memory mapping of the resulting executable, I see:
12345600000-12345679000 r-xp 00000000 08:01 1 /path/to/executable
It is obvious why the section would be aligned to 0x1000, that's page size, but where does 0x100000 come from?
Now the interesting part is that this only happens when I disable build ids with -Wl,--build-id=none, or when I enable them and try to stuff the .note.gnu.build-id section right after .text.
Have a look at the generated map file. It's possible that some of your input .text sections also have their own alignment requirements.
I'm wring a toy OS for my raspberry pi and trying to setup the MMU. I want to split the virtual memory between 3G:1G, so I think my code should be linked at 0xC0008000, while loaded to 0x8000 on execution. (The 0x8000 is the address the current bootloaders expect to find the kernel - since they are built for linux).
I think everything is setup fine by poking around with objdump, but it doesn't work. After some debugging with qemu, I think the bootloader doesn't find my code at all.
I believe the problem is with my linkscript, since the kernel starts fine if I move the starting code into its own section that's both linked and loaded at 0x8000.
I've extracted out the script and the minimal code. As following,
$ cat kernel.ld
ENTRY(_start)
SECTIONS
{
/* must == KERNLINK */
. = 0xC0008000;
.text : AT(0x8000) {
*(.text)
}
.bss : {
*(.bss)
}
.data : {
*(.data)
}
.rodata : {
*(.rodata)
}
}
-
$ cat source/entry.S
#include "mem.h"
.globl _start
_start = V2P(entry)
.globl entry
entry:
loop$:
b loop$
(The "b loop$" won't work since it's generated as "b·c0008000" instead of using a relative branch. But never mind that part, the problem is it never reaches entry).
$ cat source/mem.h
#define KERNLOAD 0x8000
#define KERNBASE 0xC0000000
#define KERNLINK (KERNBASE+KERNLOAD)
#define V2P(va) ((va) - KERNBASE)
Those are the only three source files. There should be nothing interesting in the Makefile, but the output from make is,
$ make
arm-none-eabi-gcc -g -Wall -c -o build/entry.o source/entry.S
arm-none-eabi-ld --no-undefined -T kernel.ld build/entry.o -Map kernel.map -o build/output.elf
arm-none-eabi-objcopy build/output.elf -O binary kernel.img
And objdump,
$ arm-none-eabi-objdump -h build/output.elf
build/output.elf: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000004 c0008000 00008000 00008000 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .ARM.attributes 00000014 00000000 00000000 00008004 2**0
CONTENTS, READONLY
2 .debug_line 0000003c 00000000 00000000 00008018 2**0
CONTENTS, READONLY, DEBUGGING
3 .debug_info 00000054 00000000 00000000 00008054 2**0
CONTENTS, READONLY, DEBUGGING
4 .debug_abbrev 00000014 00000000 00000000 000080a8 2**0
CONTENTS, READONLY, DEBUGGING
5 .debug_aranges 00000020 00000000 00000000 000080c0 2**3
CONTENTS, READONLY, DEBUGGING
I start to believe I overlooked some obvious yet precious details.
==== update ====
As noted in my own answer below, the confusion is caused by debugging in qemu. The breakpoints are set by virtual addresses. "b entry" doesn't work, because gdb is thinking about virtual address while MMU hasn't been enabled and we're running by physical address.
So before MMU is enabled, we have to use "b *0x8000". This sets a breakpoint that's correctly hit. GDB seems still confused though, since it doesn't show any debugging info (no source code, like 0x00008004 in ?? ()). That's not a big issue since I have the listing produced by "objdump -D".
After MMU is enabled and we branch to main, gdb works perfectly. The crux is to jump to a virtual address, using an absolute branch. b/bl would issue relative jumps. So I use ldr pc =main. bx works too.
Finally solved it...
The code and the linkscript don't have problems. It's just that debugging doesn't seem to work on the qemu I used. It does work when VMA==LMA, but in this case the kernel already runs and qemu doesn't know about it. Or, the breakpoint is lost and never caught by gdb.
Anyway, by starting afresh and adding bits one by one, I have it working on my rpi (real hardware), and then it works on qemu too (gdb still won't catch the breakpoint).
So my question should really be how to debug such a scenario using qemu/gdb.
(My original problem is solved by changing the "domain" permission to "manager", instead of using "client". Yeah I know this is probably temporary and I should set a variable elsewhere).
I am a bit confused by the results I am getting when I use my toolchain's (Yagarto and codesourcery) size utility. it is reporting that I am using 0 bytes in the data section. see below
$ arm-none-eabi-size.exe rest-server-example.crazy-horse.elf
text data bss dec hex filename
79364 0 34288 113652 1bbf4 rest-server-example.crazy-horse.elf
I know my code is using and initializing static RAM variables to values other than 0.
interestingly enough when I pass the size tool directly some of the object files that are getting linked I see .data section being reported
example:
text data bss dec hex filename
1648 0 20 1668 684 obj_crazy-horse/uip-nd6.o
200 12 2652 2864 b30 obj_crazy-horse/uip-packetqueue.o
12 0 0 12 c obj_crazy-horse/uip-split.o
1816 24 48 1888 760 obj_crazy-horse/usb-core.o
284 0 0 284 11c obj_crazy-horse/usb-interrupt.o
2064 20 188 2272 8e0 obj_crazy-horse/xmac.o
Why would the elf file report 0 for the .data section when the object files that make it are reporting non-zero values?
FYI I am working on embedded software for a AT91SAM7x256 Micro
edit:
adding the CFLAGS and LDFLAGS
CFLAGS += -O -DRUN_AS_SYSTEM -DROM_RUN -ffunction-sections
LDFLAGS += -L $(CPU_DIRECTORY) -T $(LINKERSCRIPT) -nostartfiles -Wl,-Map,$(TARGET).map
edit #2:
from the object dump we can clearly see that the .data section has data assigned to it but the size utility is not picking it up for some reason
objdump link
All I am looking for is to get an exact usage of my RAM I am not trying to figure out whether one of my variables was optimized out.
edit 3:
more information showing that the size utility does see something in the .data section
$ arm-none-eabi-size.exe -A -t -x rest-server-example.crazy-horse.elf
rest-server-example.crazy-horse.elf :
section size addr
.vectrom 0x34 0x100000
.text 0x10fc8 0x100038
.rodata 0x149c 0x111000
.ARM.extab 0x30 0x11249c
.ARM.exidx 0xe0 0x1124cc
.data 0x1028 0x200000
.bss 0x7bec 0x201028
.stack 0xa08 0x20f5f8
.ARM.attributes 0x32 0x0
.comment 0x11 0x0
.debug_aranges 0xc68 0x0
.debug_info 0x2b87e 0x0
.debug_abbrev 0x960b 0x0
.debug_line 0x9bcb 0x0
.debug_frame 0x4918 0x0
.debug_str 0x831d 0x0
.debug_loc 0x13fad 0x0
.debug_ranges 0x620 0x0
Total 0x7c4c5
My interpretation would be that the linker script creates a single loadable section, which contains the initial values of the data section and a piece of startup code that copies the data to the uninitialized data section.
This is necessary if you want to have a single image file that can be run from read-only memory, as there is no ELF loader in front then that would perform that copy for you.
Normally, this is only done in the section to segment mapping (i.e. the output sections are arranged in the linker script using the > section placement command) rather than by mapping the input section twice, but that is certainly possible as well.
The usage numbers are quite accurate: the text size is the amount of Flash space needed, the BSS size is the amount of RAM needed. Initialized data is counted twice, once for the initial data in Flash, and once for the modifiable data in RAM.
Your .data section have the CODE attribute set, and this confuses "arm-none-eabi-size". The size of the .data section is incorrectly added to the total text size instead of the data size.
My guess is that you have some code that is stored in flash but is copied to ram at run time such as a fast interrupt handler or flash reprogramming that must run from RAM. This will set the CODE attribute for the data segment, and "size" believes that all of .data is text.