LD:使用ALIGN()的不同方法

时间:2019-03-12 11:53:23

标签: gcc linker ld memory-alignment

这些有什么区别?

mysection ALIGN(4): {...}

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

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

结果是否相同?

2 个答案:

答案 0 :(得分: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。 然后在.mysection开始之后将位置计数器对准0x10008, 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与0x10004之后的第一个8字节边界0x10008对齐。但是. = 0x20004; 将位置计数器移到碰巧不是8字节对齐的地址,因此.section_b 及其第一个对象bb的字节数不为8字节。确实,如果我们删除了. = 0x20004;.section_b和对象bb将被放置在aa之后0x10009处。

答案 1 :(得分:0)

我根据@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