LD: разные способы использования ALIGN()

#gcc #linker #ld #memory-alignment

#gcc #компоновщик #ld #выравнивание по памяти

Вопрос:

В чем разница между ними?

 mysection ALIGN(4): {...}
  

и

 mysection: {. = ALIGN(4); ...}
  

и

 . = ALIGN(4); 
mysection: {...}
  

Совпадают ли результаты?

Ответ №1:

Смотрите:

 $ cat foo.c
int mysym __attribute__((section(".mysection"))) = 42;

$ gcc -c foo.c
  

Пример 1

 $ cat foo_1.lds
SECTIONS
{
    . = 0x10004;
    .mysection ALIGN(8): {
        *(.mysection)
    }
}

$ ld -T foo_1.lds foo.o -o foo1.out
$ readelf -s foo1.out

Symbol table '.symtab' contains 5 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000010008     0 SECTION LOCAL  DEFAULT    1 
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    2 
     3: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS foo.c
     4: 0000000000010008     4 OBJECT  GLOBAL DEFAULT    1 mysym

$ readelf -t foo1.out | grep -A3 '.mysection'
  [ 1] .mysection
       PROGBITS               PROGBITS         0000000000010008  0000000000010008  0
       0000000000000004 0000000000000000  0                 4
       [0000000000000003]: WRITE, ALLOC
  

Случай 2

 $ cat foo_2.lds
SECTIONS
{
    . = 0x10004;
    . = ALIGN(8);
    .mysection : {
        *(.mysection)
    }
}

$ ld -T foo_2.lds foo.o -o foo2.out
$ readelf -s foo2.out 

Symbol table '.symtab' contains 5 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000010008     0 SECTION LOCAL  DEFAULT    1 
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    2 
     3: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS foo.c
     4: 0000000000010008     4 OBJECT  GLOBAL DEFAULT    1 mysym

$ readelf -t foo2.out | grep -A3 '.mysection'
  [ 1] .mysection
       PROGBITS               PROGBITS         0000000000010008  0000000000010008  0
       0000000000000004 0000000000000000  0                 4
       [0000000000000003]: WRITE, ALLOC
  

Пример 3

 $ cat foo_3.lds
SECTIONS
{
    . = 0x10004;
    .mysection : {
        . = ALIGN(8);
        *(.mysection)
    }
}

$ ld -T foo_3.lds foo.o -o foo3.out
$ readelf -s foo3.out 

Symbol table '.symtab' contains 5 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000010004     0 SECTION LOCAL  DEFAULT    1 
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    2 
     3: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS foo.c
     4: 0000000000010008     4 OBJECT  GLOBAL DEFAULT    1 mysym

$ readelf -t foo3.out | grep -A3 '.mysection'
  [ 1] .mysection
       PROGBITS               PROGBITS         0000000000010004  0000000000010004  0
       0000000000000008 0000000000000000  0                 4
       [0000000000000003]: WRITE, ALLOC
  

Итак, случай 1 эквивалентен случаю 2 . Оба они выравнивают .mysection по
следующая 8-байтовая граница, 0x10008, после 0x10004 и mysym находится по тому же адресу.

Но случай 3 не выравнивает .mysection значение 0x10008. Он остается на 0x10004 . Затем счетчик местоположения выравнивается на 0x10008 после начала .mysection и mysym находится по этому адресу.

Во всех случаях адрес первого символа в .mysection равен 0x10008, но только в случае 1 и случае 2 адрес .mysection

Позже

Как влияет случай 2, если у меня есть несколько разделов, размещенных в разных областях памяти?

Всякий раз, когда скрипт вызывает:

 . = ALIGN(N);
  

он просто устанавливает счетчик местоположения на следующую N выровненную границу в байтах после
его текущее положение. Вот и все. Итак:

Пример 4

 $ cat bar.c
char aa __attribute__((section(".section_a"))) = 0;
char bb __attribute__((section(".section_b"))) = 0;

$ cat bar.lds 
SECTIONS
{
    . = 0x10004;
    . = ALIGN(8);
    .section_a : {
        *(.section_a)
    }
    . = 0x20004;
    .section_b : {
        *(.section_b)
    }
}

$ gcc -c bar.c
$ ld -T bar.lds bar.o -o bar.out

$ readelf -s bar.out

Symbol table '.symtab' contains 7 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000010008     0 SECTION LOCAL  DEFAULT    1 
     2: 0000000000020004     0 SECTION LOCAL  DEFAULT    2 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS bar.c
     5: 0000000000020004     1 OBJECT  GLOBAL DEFAULT    2 bb
     6: 0000000000010008     1 OBJECT  GLOBAL DEFAULT    1 aa

$ readelf -t bar.out | egrep -A3 '(section_a|section_b)'
  [ 1] .section_a
       PROGBITS               PROGBITS         0000000000010008  0000000000010008  0
       0000000000000001 0000000000000000  0                 1
       [0000000000000003]: WRITE, ALLOC
  [ 2] .section_b
       PROGBITS               PROGBITS         0000000000020004  0000000000020004  0
       0000000000000001 0000000000000000  0                 1
       [0000000000000003]: WRITE, ALLOC
  

Здесь . = ALIGN(8); имеет эффект, который .section_a и первый объект внутри него,
aa выравниваются по первой 8-байтовой границе, 0x10008, после 0x10004. Но . = 0x20004;
перемещает счетчик местоположения на адрес, который случайно не выровнен по 8 байтам, поэтому .section_b
и его первый объект bb не выровнен по 8 байтам. Действительно, если мы удалили . = 0x20004; , то
.section_b и объект bb был бы помещен сразу после aa , в 0x10009 .

Комментарии:

1. Как влияет случай 2, если у меня есть несколько разделов, размещенных в разных областях памяти?

2. @oyvind Привет. Расширенный ответ.

3. Привет, большое спасибо! Я был вдохновлен попробовать еще несколько вещей. Я вставил это в ответ из-за длины.

4. Вы можете включить это в свой ответ, чтобы у нас была вся информация в одном месте.

5. Np, для меня это подойдет. Рад, что помогли.

Ответ №2:

Я провел свой собственный эксперимент, основанный на случаях @Mike Kinghan. Цифры не совсем совпадают с его случаями, но тестируются те же методы, но с использованием нескольких областей памяти.

Наблюдения:

  1. Случай Майка 1 (мои случаи 2 и 3) вообще не удается связать.

  2. В случае Майка 2 (мой случай 1) не удается выровнять переменную bb ожидаемым образом.

  3. Случай Майка 3 (мой случай 5) успешно выравнивает переменную bb

  4. Использование SUBALIGN (мой случай 4) правильно выравнивает переменную bb , но также выравнивает каждый раздел ввода в этом разделе вывода.

Пример 1

 $ cat bar.c
char aa __attribute__((section(".section_a"))) = 0;
char bb __attribute__((section(".section_b"))) = 0;

$ gcc -c bar.c

$ cat bar1.lds
MEMORY {
    FLASH (rx)  : ORIGIN = 0x00000001, LENGTH = 0x100000
    RAM   (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000
}

SECTIONS
{
    . = 0x10004;
    . = ALIGN(8);
    .section_a : {
        *(.section_a)
    } > RAM
    _myvar = .;
    . = ALIGN(8);
    .section_b : {
        *(.section_b)
    } > FLASH
}

$ ld -T bar1.lds bar.o -o bar.out

$ readelf -s bar.out
Symbol table '.symtab' contains 8 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000020000000     0 SECTION LOCAL  DEFAULT    1
     2: 0000000000000001     0 SECTION LOCAL  DEFAULT    2
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3
     4: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS bar.c
     5: 0000000000000001     1 OBJECT  GLOBAL DEFAULT    2 bb
     6: 0000000020000000     1 OBJECT  GLOBAL DEFAULT    1 aa
     7: 0000000020000001     0 NOTYPE  GLOBAL DEFAULT    1 _myvar
  

Случай 2

 $ cat bar2.lds
MEMORY {
    FLASH (rx)  : ORIGIN = 0x00000001, LENGTH = 0x100000
    RAM   (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000
}

SECTIONS
{
    . = 0x10004;
    . = ALIGN(8);
    .section_a : {
        *(.section_a)
    } > RAM
    _myvar = .;
    .section_b ALIGN(8) : {
        *(.section_b)
    } > FLASH
}

$ ld -T bar2.lds bar.o -o bar.out
ld: address 0x20000009 of bar.out section `.section_b' is not within region `FLASH'
ld: address 0x20000009 of bar.out section `.section_b' is not within region `FLASH'
  

Пример 3

 $ cat bar3.lds
MEMORY {
    FLASH (rx)  : ORIGIN = 0x00000001, LENGTH = 0x100000
    RAM   (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000
}

SECTIONS
{
    . = 0x10004;
    . = ALIGN(8);
    .section_a : {
        *(.section_a)
    } > FLASH
    _myvar = .;
    .section_b ALIGN(8) : {
        *(.section_b)
    } > RAM
}

$ ld -T bar3.lds bar.o -o bar.out
ld: address 0x9 of bar.out section `.section_b' is not within region `RAM'
ld: address 0x9 of bar.out section `.section_b' is not within region `RAM'
  

Пример 4

 $ cat bar4.lds
MEMORY {
    FLASH (rx)  : ORIGIN = 0x00000001, LENGTH = 0x100000
    RAM   (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000
}

SECTIONS
{
    . = 0x10004;
    . = ALIGN(8);
    .section_a : {
        *(.section_a)
    } > RAM
    _myvar = .;
    .section_b : SUBALIGN(8){
        *(.section_b)
    } > FLASH
}

$ ld -T bar4.lds bar.o -o bar.out

$ readelf -s bar.out
Symbol table '.symtab' contains 8 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000020000000     0 SECTION LOCAL  DEFAULT    1
     2: 0000000000000008     0 SECTION LOCAL  DEFAULT    2
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3
     4: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS bar.c
     5: 0000000000000008     1 OBJECT  GLOBAL DEFAULT    2 bb
     6: 0000000020000000     1 OBJECT  GLOBAL DEFAULT    1 aa
     7: 0000000020000001     0 NOTYPE  GLOBAL DEFAULT    1 _myvar
  

Пример 5

 $ cat bar5.lds
MEMORY {
    FLASH (rx)  : ORIGIN = 0x00000001, LENGTH = 0x100000
    RAM   (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000
}

SECTIONS
{
    . = 0x10004;
    . = ALIGN(8);
    .section_a : {
        *(.section_a)
    } > RAM
    _myvar = .;
    .section_b : {
        . = ALIGN(8);
        *(.section_b)
    } > FLASH
}

$ ld -T bar5.lds bar.o -o bar.out

$ readelf -s bar.out
Symbol table '.symtab' contains 8 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000020000000     0 SECTION LOCAL  DEFAULT    1
     2: 0000000000000001     0 SECTION LOCAL  DEFAULT    2
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3
     4: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS bar.c
     5: 0000000000000008     1 OBJECT  GLOBAL DEFAULT    2 bb
     6: 0000000020000000     1 OBJECT  GLOBAL DEFAULT    1 aa
     7: 0000000020000001     0 NOTYPE  GLOBAL DEFAULT    1 _myvar